#include "../deps/json/json.hpp" using json = nlohmann::json; #define PROXYJSON #include // std::cout #include // std::stringstream #include #include // std::sort #include #include // std::vector #include #include "prometheus/exposer.h" #include "prometheus/counter.h" #include "openssl/ssl.h" #include "openssl/err.h" #include "Base_Thread.h" #include "MySQL_HostGroups_Manager.h" #include "PgSQL_HostGroups_Manager.h" #include "mysql.h" #include "proxysql_admin.h" #include "re2/re2.h" #include "re2/regexp.h" #include "proxysql.h" #include "proxysql_config.h" #include "proxysql_restapi.h" #include "proxysql_utils.h" #include "prometheus_helpers.h" #include "cpp.h" #include "MySQL_Data_Stream.h" #include "PgSQL_Data_Stream.h" #include "MySQL_Query_Processor.h" #include "PgSQL_Query_Processor.h" #include "ProxySQL_HTTP_Server.hpp" // HTTP server #include "MySQL_Authentication.hpp" #include "PgSQL_Authentication.h" #include "MySQL_LDAP_Authentication.hpp" #include "MySQL_PreparedStatement.h" #include "ProxySQL_Cluster.hpp" #include "ProxySQL_Statistics.hpp" #include "MySQL_Logger.hpp" #include "PgSQL_Logger.hpp" #include "MCP_Thread.h" #include "SQLite3_Server.h" #include "Web_Interface.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef SPOOKYV2 #include "SpookyV2.h" #define SPOOKYV2 #endif #include #include #include "platform.h" #include "microhttpd.h" #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || defined(__mips__)) && defined(__linux) // currently only support x86-32, x86-64, ARM, and MIPS on Linux #include "coredumper/coredumper.h" #endif #include #include "PgSQL_Protocol.h" #include "MySQL_Query_Cache.h" #include "PgSQL_Query_Cache.h" //#include "usual/time.h" using std::string; using std::unique_ptr; #ifdef WITHGCOV extern "C" void __gcov_dump(); extern "C" void __gcov_reset(); #endif #ifdef DEBUG //#define BENCHMARK_FASTROUTING_LOAD #endif // DEBUG //#define MYSQL_THREAD_IMPLEMENTATION #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" #define READ_ONLY_0 "\x01\x00\x00\x01\x01\x28\x00\x00\x02\x03\x64\x65\x66\x00\x00\x00\x12\x40\x40\x67\x6c\x6f\x62\x61\x6c\x2e\x72\x65\x61\x64\x5f\x6f\x6e\x6c\x79\x00\x0c\x3f\x00\x01\x00\x00\x00\x08\x80\x00\x00\x00\x00\x05\x00\x00\x03\xfe\x00\x00\x02\x00\x02\x00\x00\x04\x01\x30\x05\x00\x00\x05\xfe\x00\x00\x02\x00" #define READ_ONLY_1 "\x01\x00\x00\x01\x01\x28\x00\x00\x02\x03\x64\x65\x66\x00\x00\x00\x12\x40\x40\x67\x6c\x6f\x62\x61\x6c\x2e\x72\x65\x61\x64\x5f\x6f\x6e\x6c\x79\x00\x0c\x3f\x00\x01\x00\x00\x00\x08\x80\x00\x00\x00\x00\x05\x00\x00\x03\xfe\x00\x00\x02\x00\x02\x00\x00\x04\x01\x31\x05\x00\x00\x05\xfe\x00\x00\x02\x00" struct MHD_Daemon *Admin_HTTP_Server; extern ProxySQL_Statistics *GloProxyStats; template int ProxySQL_Test___PurgeDigestTable(bool async_purge, bool parallel, char **msg); extern char *ssl_key_fp; extern char *ssl_cert_fp; extern char *ssl_ca_fp; // ProxySQL_Admin shared variables int admin___web_verbosity = 0; char * proxysql_version = NULL; #include "proxysql_find_charset.h" template ::value, bool>::type = true> T j_get_srv_default_int_val( const json& j, uint32_t hid, const string& key, const function& val_check); static const vector mysql_servers_tablenames = { "mysql_servers", "mysql_replication_hostgroups", "mysql_group_replication_hostgroups", "mysql_galera_hostgroups", "mysql_aws_aurora_hostgroups", "mysql_hostgroup_attributes", "mysql_servers_ssl_params", }; static const vector pgsql_servers_tablenames = { "pgsql_servers", "pgsql_replication_hostgroups", // "pgsql_group_replication_hostgroups", // "pgsql_galera_hostgroups", // "pgsql_aws_aurora_hostgroups", "pgsql_hostgroup_attributes", }; static const vector mysql_firewall_tablenames = { "mysql_firewall_whitelist_users", "mysql_firewall_whitelist_rules", "mysql_firewall_whitelist_sqli_fingerprints", }; static const vector pgsql_firewall_tablenames = { "pgsql_firewall_whitelist_users", "pgsql_firewall_whitelist_rules", "pgsql_firewall_whitelist_sqli_fingerprints", }; static const vector mysql_query_rules_tablenames = { "mysql_query_rules", "mysql_query_rules_fast_routing" }; static const vector pgsql_query_rules_tablenames = { "pgsql_query_rules", "pgsql_query_rules_fast_routing" }; static const vector scheduler_tablenames = { "scheduler" }; static const vector proxysql_servers_tablenames = { "proxysql_servers" }; static const vector restapi_tablenames = { "restapi_routes" }; static unordered_map&> module_tablenames = { { "mysql_servers", mysql_servers_tablenames }, { "mysql_firewall", mysql_firewall_tablenames }, { "mysql_query_rules", mysql_query_rules_tablenames }, { "scheduler", scheduler_tablenames }, { "proxysql_servers", proxysql_servers_tablenames }, { "restapi", restapi_tablenames }, { "pgsql_servers", pgsql_servers_tablenames }, { "pgsql_firewall", pgsql_firewall_tablenames }, { "pgsql_query_rules", pgsql_query_rules_tablenames }, }; static void BQE1(SQLite3DB *db, const vector& tbs, const string& p1, const string& p2, const string& p3) { string query; for (auto it = tbs.begin(); it != tbs.end(); it++) { if (p1 != "") { query = p1 + *it; db->execute(query.c_str()); } if (p2 != "" && p3 != "") { query = p2 + *it + p3 + *it; db->execute(query.c_str()); } } } static int round_intv_to_time_interval(const char* name, int _intv) { int intv = _intv; if (intv > 300) { intv = 600; } else { if (intv > 120) { intv = 300; } else { if (intv > 60) { intv = 120; } else { if (intv > 30) { intv = 60; } else { if (intv > 10) { intv = 30; } else { if (intv > 5) { intv = 10; } else { if (intv > 1) { intv = 5; } } } } } } } if (intv != _intv) { proxy_warning("Variable '%s' rounded to interval '%d'\n", name, intv); } return intv; } #ifdef __APPLE__ #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif // MSG_NOSIGNAL #endif // __APPLE__ #define SAFE_SQLITE3_STEP(_stmt) do {\ do {\ rc=(*proxy_sqlite3_step)(_stmt);\ if (rc!=SQLITE_DONE) {\ assert(rc==SQLITE_LOCKED);\ usleep(100);\ }\ } while (rc!=SQLITE_DONE);\ } while (0) typedef struct _arg_proxysql_adm_t { struct sockaddr * addr; socklen_t addr_size; int client_t; } arg_proxysql_adm; 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; }; char *s_strdup(char *s) { char *ret=NULL; if (s) { ret=strdup(s); } return ret; } int admin_load_main_=0; bool admin_nostart_=false; int __admin_refresh_interval=0; bool admin_proxysql_mysql_paused = false; bool admin_proxysql_pgsql_paused = false; int admin_old_wait_timeout; extern MySQL_Query_Cache *GloMyQC; extern PgSQL_Query_Cache* GloPgQC; extern MySQL_Authentication *GloMyAuth; extern PgSQL_Authentication *GloPgAuth; extern MySQL_LDAP_Authentication *GloMyLdapAuth; extern ProxySQL_Admin *GloAdmin; extern MySQL_Query_Processor* GloMyQPro; extern PgSQL_Query_Processor* GloPgQPro; extern MySQL_Threads_Handler *GloMTH; extern MySQL_Logger *GloMyLogger; extern PgSQL_Logger* GloPgSQL_Logger; extern MySQL_STMT_Manager_v14 *GloMyStmt; extern MySQL_Monitor *GloMyMon; extern PgSQL_Threads_Handler* GloPTH; extern MCP_Threads_Handler* GloMCPH; extern void (*flush_logs_function)(); extern Web_Interface *GloWebInterface; extern ProxySQL_Cluster *GloProxyCluster; #ifdef PROXYSQLCLICKHOUSE extern ClickHouse_Authentication *GloClickHouseAuth; extern ClickHouse_Server *GloClickHouseServer; #endif /* PROXYSQLCLICKHOUSE */ extern SQLite3_Server *GloSQLite3Server; extern char * binary_sha1; extern int ProxySQL_create_or_load_TLS(bool bootstrap, std::string& msg); #define PANIC(msg) { perror(msg); exit(EXIT_FAILURE); } pthread_mutex_t sock_mutex = PTHREAD_MUTEX_INITIALIZER; //pthread_mutex_t admin_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t users_mutex = PTHREAD_MUTEX_INITIALIZER; //pthread_mutex_t test_mysql_firewall_whitelist_mutex = PTHREAD_MUTEX_INITIALIZER; //std::unordered_map map_test_mysql_firewall_whitelist_rules; //char rand_del[6]; //static int http_handler(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **ptr) { MHD_Result http_handler(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, long unsigned int *upload_data_size, void **ptr) { return (MHD_Result) GloAdmin->AdminHTTPServer->handler(cls, connection, url, method, version, upload_data, upload_data_size, ptr); } #define LINESIZE 2048 #include "ProxySQL_Admin_Tables_Definitions.h" static char * admin_variables_names[]= { (char *)"admin_credentials", (char *)"stats_credentials", (char *)"stats_mysql_connections", (char *)"stats_mysql_connection_pool", (char *)"stats_mysql_query_cache", (char *)"stats_mysql_query_digest_to_disk", (char *)"stats_system_cpu", (char *)"stats_system_memory", (char *)"mysql_ifaces", (char *)"pgsql_ifaces", (char *)"telnet_admin_ifaces", (char *)"telnet_stats_ifaces", (char *)"refresh_interval", (char *)"read_only", // (char *)"hash_passwords", (char *)"vacuum_stats", (char *)"version", (char *)"cluster_username", (char *)"cluster_password", (char *)"cluster_check_interval_ms", (char *)"cluster_check_status_frequency", (char *)"cluster_mysql_query_rules_diffs_before_sync", (char *)"cluster_mysql_servers_diffs_before_sync", (char *)"cluster_mysql_users_diffs_before_sync", (char *)"cluster_proxysql_servers_diffs_before_sync", (char *)"cluster_mysql_variables_diffs_before_sync", (char *)"cluster_admin_variables_diffs_before_sync", (char *)"cluster_ldap_variables_diffs_before_sync", (char *)"cluster_mysql_query_rules_save_to_disk", (char *)"cluster_mysql_servers_save_to_disk", (char *)"cluster_mysql_users_save_to_disk", (char *)"cluster_proxysql_servers_save_to_disk", (char *)"cluster_mysql_variables_save_to_disk", (char *)"cluster_admin_variables_save_to_disk", (char *)"cluster_ldap_variables_save_to_disk", (char *)"cluster_mysql_servers_sync_algorithm", (char *)"checksum_mysql_query_rules", (char *)"checksum_mysql_servers", (char *)"checksum_mysql_users", (char *)"checksum_mysql_variables", (char *)"checksum_admin_variables", (char *)"checksum_ldap_variables", (char *)"restapi_enabled", (char *)"restapi_port", (char *)"web_enabled", (char *)"web_port", (char *)"web_verbosity", (char *)"prometheus_memory_metrics_interval", #ifdef DEBUG (char *)"debug", (char *)"debug_output", #endif /* DEBUG */ (char *)"coredump_generation_interval_ms", (char *)"coredump_generation_threshold", (char *)"ssl_keylog_file", NULL }; using metric_name = std::string; using metric_help = std::string; using metric_tags = std::map; using admin_counter_tuple = std::tuple< p_admin_counter::metric, metric_name, metric_help, metric_tags >; using admin_gauge_tuple = std::tuple< p_admin_gauge::metric, metric_name, metric_help, metric_tags >; using admin_dyn_counter_tuple = std::tuple< p_admin_dyn_counter::metric, metric_name, metric_help, metric_tags >; using admin_dyn_gauge_tuple = std::tuple< p_admin_dyn_gauge::metric, metric_name, metric_help, metric_tags >; using admin_counter_vector = std::vector; using admin_gauge_vector = std::vector; using admin_dyn_counter_vector = std::vector; using admin_dyn_gauge_vector = std::vector; /** * @brief Metrics map holding the metrics for the 'ProxySQL_Admin' module. * * @note Some metrics in this map, share a common "id name", because * they differ only by label, because of this, HELP is shared between * them. For better visual identification of this groups they are * sepparated using a line separator comment. */ const std::tuple admin_metrics_map = std::make_tuple( admin_counter_vector { std::make_tuple ( p_admin_counter::uptime, "proxysql_uptime_seconds_total", "The total uptime of ProxySQL.", metric_tags {} ), std::make_tuple ( p_admin_counter::jemalloc_allocated, "proxysql_jemalloc_allocated_bytes_total", "Bytes allocated by the application.", metric_tags {} ) }, admin_gauge_vector { std::make_tuple ( p_admin_gauge::mysql_listener_paused, "proxysql_mysql_listener_paused", "MySQL listener paused because of PROXYSQL PAUSE.", metric_tags {} ), std::make_tuple( p_admin_gauge::pgsql_listener_paused, "proxysql_pgsql_listener_paused", "PgSQL listener paused because of PROXYSQL PAUSE.", metric_tags {} ), // memory metrics std::make_tuple ( p_admin_gauge::connpool_memory_bytes, "proxysql_connpool_memory_bytes", "Memory used by the connection pool to store connections metadata.", metric_tags {} ), std::make_tuple ( p_admin_gauge::sqlite3_memory_bytes, "proxysql_sqlite3_memory_bytes", "Memory used by SQLite.", metric_tags {} ), // ==================================================================== std::make_tuple ( p_admin_gauge::jemalloc_resident, "proxysql_jemalloc_bytes", "Jemalloc memory usage stadistics (resident|active|mapped|metadata).", metric_tags { { "type", "resident" } } ), std::make_tuple ( p_admin_gauge::jemalloc_active, "proxysql_jemalloc_bytes", "Jemalloc memory usage stadistics (resident|active|mapped|metadata).", metric_tags { { "type", "active" } } ), std::make_tuple ( p_admin_gauge::jemalloc_mapped, "proxysql_jemalloc_bytes", "Jemalloc memory usage stadistics (resident|active|mapped|metadata).", metric_tags { { "type", "mapped" } } ), std::make_tuple ( p_admin_gauge::jemalloc_metadata, "proxysql_jemalloc_bytes", "Jemalloc memory usage stadistics (resident|active|mapped|metadata).", metric_tags { { "type", "metadata" } } ), std::make_tuple ( p_admin_gauge::jemalloc_retained, "proxysql_jemalloc_bytes", "Jemalloc memory usage stadistics (resident|active|mapped|metadata).", metric_tags { { "type", "retained" } } ), // ==================================================================== std::make_tuple ( p_admin_gauge::query_digest_memory_bytes, "proxysql_query_digest_memory_bytes", "Memory used to store data related to stats_mysql_query_digest.", metric_tags {} ), std::make_tuple ( p_admin_gauge::auth_memory_bytes, "proxysql_auth_memory_bytes", "Memory used by the authentication module to store user credentials and attributes.", metric_tags {} ), std::make_tuple ( p_admin_gauge::mysql_query_rules_memory_bytes, "proxysql_mysql_query_rules_memory_bytes", "Number of bytes used by 'mysql_query_rules' rules.", metric_tags {} ), std::make_tuple ( p_admin_gauge::mysql_firewall_users_table, "proxysql_mysql_firewall_users_table_bytes", "Number of bytes used by 'mysql_firewall_users' entries.", metric_tags {} ), std::make_tuple ( // TODO: Check why 'global_firewall_whitelist_users_result___size' never updated p_admin_gauge::mysql_firewall_users_config, "proxysql_mysql_firewall_users_config_bytes", "Full 'mysql_firewall_users' config 'resultset' size.", metric_tags {} ), std::make_tuple ( p_admin_gauge::mysql_firewall_rules_table, "proxysql_mysql_firewall_rules_table_bytes", "Number of bytes used by 'mysql_firewall_rules' entries.", metric_tags {} ), std::make_tuple ( p_admin_gauge::mysql_firewall_rules_config, "proxysql_mysql_firewall_rules_config_bytes", "Full 'mysql_firewall_users' config 'resultset' size.", metric_tags {} ), std::make_tuple ( p_admin_gauge::stack_memory_mysql_threads, "proxysql_stack_memory_mysql_threads_bytes", "Stack size used by 'mysql_threads'.", metric_tags {} ), std::make_tuple ( p_admin_gauge::stack_memory_admin_threads, "proxysql_stack_memory_admin_threads_bytes", "Stack size used by 'admin_threads'.", metric_tags {} ), std::make_tuple ( p_admin_gauge::stack_memory_cluster_threads, "proxysql_stack_memory_cluster_threads", "Stack size used by 'cluster_threads'.", metric_tags {} ), // stmt metrics std::make_tuple ( p_admin_gauge::stmt_client_active_total, "proxysql_stmt_client_active", "The total number of prepared statements that are in use by clients.", metric_tags {} ), std::make_tuple ( p_admin_gauge::stmt_client_active_unique, "proxysql_stmt_client_active_unique", "This variable tracks the number of unique prepared statements currently in use by clients.", metric_tags {} ), std::make_tuple ( p_admin_gauge::stmt_server_active_total, "proxysql_stmt_server_active", "The total number of prepared statements currently available across all backend connections.", metric_tags {} ), std::make_tuple ( p_admin_gauge::stmt_server_active_unique, "proxysql_stmt_server_active_unique", "The number of unique prepared statements currently available across all backend connections.", metric_tags {} ), std::make_tuple ( p_admin_gauge::stmt_max_stmt_id, "proxysql_stmt_max_stmt_id", "When a new global prepared statement is created, a new \"stmt_id\" is used. Stmt_Max_Stmt_id represents the maximum \"stmt_id\" ever used.", metric_tags {} ), std::make_tuple ( p_admin_gauge::stmt_cached, "proxysql_stmt_cached", "This is the number of global prepared statements for which proxysql has metadata.", metric_tags {} ), std::make_tuple( p_admin_gauge::prepare_stmt_metadata_memory_bytes, "prepare_stmt_metadata_memory_bytes", "Memory used to store meta data related to prepare statements.", metric_tags{} ), std::make_tuple( p_admin_gauge::prepare_stmt_backend_memory_bytes, "prepare_stmt_backend_memory_bytes", "Memory used by backend server related to prepare statements.", metric_tags{} ), std::make_tuple ( p_admin_gauge::fds_in_use, "proxysql_fds_in_use", "The number of file descriptors currently in use by ProxySQL.", metric_tags {} ), std::make_tuple ( p_admin_gauge::version_info, "proxysql_version_info", "ProxySQL version.", metric_tags { { "version", PROXYSQL_VERSION }, { "version_comment", std::string { "ProxySQL version " } + PROXYSQL_VERSION + ", codename " + PROXYSQL_CODENAME } } ) }, admin_dyn_counter_vector {}, admin_dyn_gauge_vector { std::make_tuple ( p_admin_dyn_gauge::proxysql_servers_clients_status_last_seen_at, "proxysql_servers_clients_status_last_seen_at", "Last time a query was executed in the local Admin interface by the remote ProxySQL instance.", metric_tags {} ) } ); ProxySQL_Admin *SPA=NULL; void * (*child_func[3]) (void *arg); const std::vector LOAD_ADMIN_VARIABLES_TO_MEMORY = { "LOAD ADMIN VARIABLES TO MEMORY" , "LOAD ADMIN VARIABLES TO MEM" , "LOAD ADMIN VARIABLES FROM DISK" }; const std::vector SAVE_ADMIN_VARIABLES_FROM_MEMORY = { "SAVE ADMIN VARIABLES FROM MEMORY" , "SAVE ADMIN VARIABLES FROM MEM" , "SAVE ADMIN VARIABLES TO DISK" }; const std::vector LOAD_ADMIN_VARIABLES_FROM_MEMORY = { "LOAD ADMIN VARIABLES FROM MEMORY" , "LOAD ADMIN VARIABLES FROM MEM" , "LOAD ADMIN VARIABLES TO RUNTIME" , "LOAD ADMIN VARIABLES TO RUN" }; const std::vector SAVE_ADMIN_VARIABLES_TO_MEMORY = { "SAVE ADMIN VARIABLES TO MEMORY" , "SAVE ADMIN VARIABLES TO MEM" , "SAVE ADMIN VARIABLES FROM RUNTIME" , "SAVE ADMIN VARIABLES FROM RUN" }; const std::vector LOAD_MYSQL_SERVERS_FROM_MEMORY = { "LOAD MYSQL SERVERS FROM MEMORY" , "LOAD MYSQL SERVERS FROM MEM" , "LOAD MYSQL SERVERS TO RUNTIME" , "LOAD MYSQL SERVERS TO RUN" }; const std::vector SAVE_MYSQL_SERVERS_TO_MEMORY = { "SAVE MYSQL SERVERS TO MEMORY" , "SAVE MYSQL SERVERS TO MEM" , "SAVE MYSQL SERVERS FROM RUNTIME" , "SAVE MYSQL SERVERS FROM RUN" }; const std::vector LOAD_MYSQL_USERS_FROM_MEMORY = { "LOAD MYSQL USERS FROM MEMORY" , "LOAD MYSQL USERS FROM MEM" , "LOAD MYSQL USERS TO RUNTIME" , "LOAD MYSQL USERS TO RUN" }; const std::vector SAVE_MYSQL_USERS_TO_MEMORY = { "SAVE MYSQL USERS TO MEMORY" , "SAVE MYSQL USERS TO MEM" , "SAVE MYSQL USERS FROM RUNTIME" , "SAVE MYSQL USERS FROM RUN" }; const std::vector LOAD_MYSQL_VARIABLES_FROM_MEMORY = { "LOAD MYSQL VARIABLES FROM MEMORY" , "LOAD MYSQL VARIABLES FROM MEM" , "LOAD MYSQL VARIABLES TO RUNTIME" , "LOAD MYSQL VARIABLES TO RUN" }; const std::vector SAVE_MYSQL_VARIABLES_TO_MEMORY = { "SAVE MYSQL VARIABLES TO MEMORY" , "SAVE MYSQL VARIABLES TO MEM" , "SAVE MYSQL VARIABLES FROM RUNTIME" , "SAVE MYSQL VARIABLES FROM RUN" }; // PgSQL const std::vector LOAD_PGSQL_SERVERS_FROM_MEMORY = { "LOAD PGSQL SERVERS FROM MEMORY" , "LOAD PGSQL SERVERS FROM MEM" , "LOAD PGSQL SERVERS TO RUNTIME" , "LOAD PGSQL SERVERS TO RUN" }; const std::vector SAVE_PGSQL_SERVERS_TO_MEMORY = { "SAVE PGSQL SERVERS TO MEMORY" , "SAVE PGSQL SERVERS TO MEM" , "SAVE PGSQL SERVERS FROM RUNTIME" , "SAVE PGSQL SERVERS FROM RUN" }; const std::vector LOAD_PGSQL_USERS_FROM_MEMORY = { "LOAD PGSQL USERS FROM MEMORY" , "LOAD PGSQL USERS FROM MEM" , "LOAD PGSQL USERS TO RUNTIME" , "LOAD PGSQL USERS TO RUN" }; const std::vector SAVE_PGSQL_USERS_TO_MEMORY = { "SAVE PGSQL USERS TO MEMORY" , "SAVE PGSQL USERS TO MEM" , "SAVE PGSQL USERS FROM RUNTIME" , "SAVE PGSQL USERS FROM RUN" }; const std::vector LOAD_PGSQL_VARIABLES_FROM_MEMORY = { "LOAD PGSQL VARIABLES FROM MEMORY" , "LOAD PGSQL VARIABLES FROM MEM" , "LOAD PGSQL VARIABLES TO RUNTIME" , "LOAD PGSQL VARIABLES TO RUN" }; const std::vector SAVE_PGSQL_VARIABLES_TO_MEMORY = { "SAVE PGSQL VARIABLES TO MEMORY" , "SAVE PGSQL VARIABLES TO MEM" , "SAVE PGSQL VARIABLES FROM RUNTIME" , "SAVE PGSQL VARIABLES FROM RUN" }; // const std::vector LOAD_COREDUMP_FROM_MEMORY = { "LOAD COREDUMP FROM MEMORY" , "LOAD COREDUMP FROM MEM" , "LOAD COREDUMP TO RUNTIME" , "LOAD COREDUMP TO RUN" }; unordered_map, vector>> load_save_disk_commands; static void generate_load_save_disk_commands(std::vector& vec1, std::vector& vec2, const string& name) { string s; if (vec1.size() == 0) { s = "LOAD " + name + " TO MEMORY"; vec1.push_back(s); s = "LOAD " + name + " TO MEM"; vec1.push_back(s); s = "LOAD " + name + " FROM DISK"; vec1.push_back(s); } if (vec2.size() == 0) { s = "SAVE " + name + " FROM MEMORY"; vec2.push_back(s); s = "SAVE " + name + " FROM MEM"; vec2.push_back(s); s = "SAVE " + name + " TO DISK"; vec2.push_back(s); } } static void generate_load_save_disk_commands(const string& name, const string& command) { std::vector vec1; std::vector vec2; generate_load_save_disk_commands(vec1, vec2, command); std::tuple, vector> a = tuple, vector>{command, vec1, vec2}; load_save_disk_commands[name] = a; } bool is_admin_command_or_alias(const std::vector& cmds, char *query_no_space, int query_no_space_length); incoming_servers_t::incoming_servers_t() {} incoming_servers_t::incoming_servers_t( SQLite3_result* incoming_mysql_servers_v2, SQLite3_result* incoming_replication_hostgroups, SQLite3_result* incoming_group_replication_hostgroups, SQLite3_result* incoming_galera_hostgroups, SQLite3_result* incoming_aurora_hostgroups, SQLite3_result* incoming_hostgroup_attributes, SQLite3_result* incoming_mysql_servers_ssl_params, SQLite3_result* runtime_mysql_servers ) : incoming_mysql_servers_v2(incoming_mysql_servers_v2), incoming_replication_hostgroups(incoming_replication_hostgroups), incoming_group_replication_hostgroups(incoming_group_replication_hostgroups), incoming_galera_hostgroups(incoming_galera_hostgroups), incoming_aurora_hostgroups(incoming_aurora_hostgroups), incoming_hostgroup_attributes(incoming_hostgroup_attributes), incoming_mysql_servers_ssl_params(incoming_mysql_servers_ssl_params), runtime_mysql_servers(runtime_mysql_servers) {} runtime_mysql_servers_checksum_t::runtime_mysql_servers_checksum_t() : epoch(0) {} runtime_mysql_servers_checksum_t::runtime_mysql_servers_checksum_t(const std::string& checksum, time_t epoch) : value(checksum), epoch(epoch) {} mysql_servers_v2_checksum_t::mysql_servers_v2_checksum_t() : epoch(0) {} mysql_servers_v2_checksum_t::mysql_servers_v2_checksum_t(const std::string& checksum, time_t epoch) : value(checksum), epoch(epoch) {} runtime_pgsql_servers_checksum_t::runtime_pgsql_servers_checksum_t() : epoch(0) {} runtime_pgsql_servers_checksum_t::runtime_pgsql_servers_checksum_t(const std::string& checksum, time_t epoch) : value(checksum), epoch(epoch) {} pgsql_servers_v2_checksum_t::pgsql_servers_v2_checksum_t() : epoch(0) {} pgsql_servers_v2_checksum_t::pgsql_servers_v2_checksum_t(const std::string& checksum, time_t epoch) : value(checksum), epoch(epoch) {} incoming_pgsql_servers_t::incoming_pgsql_servers_t() {} incoming_pgsql_servers_t::incoming_pgsql_servers_t( SQLite3_result* incoming_pgsql_servers_v2, SQLite3_result* incoming_replication_hostgroups, SQLite3_result* incoming_hostgroup_attributes, SQLite3_result* runtime_pgsql_servers ) : incoming_pgsql_servers_v2(incoming_pgsql_servers_v2), incoming_replication_hostgroups(incoming_replication_hostgroups), incoming_hostgroup_attributes(incoming_hostgroup_attributes), runtime_pgsql_servers(runtime_pgsql_servers) {} peer_runtime_mysql_servers_t::peer_runtime_mysql_servers_t() : resultset(nullptr), checksum() {} peer_runtime_mysql_servers_t::peer_runtime_mysql_servers_t( SQLite3_result* resultset, const runtime_mysql_servers_checksum_t& checksum ) : resultset(resultset), checksum(checksum) {} peer_mysql_servers_v2_t::peer_mysql_servers_v2_t() : resultset(nullptr), checksum() {} peer_mysql_servers_v2_t::peer_mysql_servers_v2_t( SQLite3_result* resultset, const mysql_servers_v2_checksum_t& checksum ) : resultset(resultset), checksum(checksum) {} peer_runtime_pgsql_servers_t::peer_runtime_pgsql_servers_t() : resultset(nullptr), checksum() {} peer_runtime_pgsql_servers_t::peer_runtime_pgsql_servers_t( SQLite3_result* resultset, const runtime_pgsql_servers_checksum_t& checksum ) : resultset(resultset), checksum(checksum) {} peer_pgsql_servers_v2_t::peer_pgsql_servers_v2_t() : resultset(nullptr), checksum() {} peer_pgsql_servers_v2_t::peer_pgsql_servers_v2_t( SQLite3_result* resultset, const pgsql_servers_v2_checksum_t& checksum ) : resultset(resultset), checksum(checksum) {} ProxySQL_Config& ProxySQL_Admin::proxysql_config() { static ProxySQL_Config instance = ProxySQL_Config(admindb); if (instance.admindb != admindb) { instance.admindb = admindb; } return instance; } ProxySQL_Restapi& ProxySQL_Admin::proxysql_restapi() { static ProxySQL_Restapi instance = ProxySQL_Restapi(admindb); if (instance.admindb != admindb) { instance.admindb = admindb; } return instance; } template int ProxySQL_Admin::FlushDigestTableToDisk(SQLite3DB *_db) { umap_query_digest uqd; umap_query_digest_text uqdt; if constexpr (pt == SERVER_TYPE_MYSQL) { if (!GloMyQPro) return 0; GloMyQPro->get_query_digests_reset(&uqd, &uqdt); } else if constexpr (pt == SERVER_TYPE_PGSQL) { if (!GloPgQPro) return 0; GloPgQPro->get_query_digests_reset(&uqd, &uqdt); } int r = uqd.size(); SQLite3DB * sdb = _db; sdb->execute("BEGIN"); int rc; sqlite3_stmt *statement1=NULL; sqlite3_stmt *statement32=NULL; char *query1=NULL; char *query32=NULL; std::string query32s = ""; if constexpr (pt == SERVER_TYPE_MYSQL) { query1 = (char*)"INSERT INTO history_mysql_query_digest VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)"; query32s = "INSERT INTO history_mysql_query_digest VALUES " + generate_multi_rows_query(32, 15); } else if constexpr (pt == SERVER_TYPE_PGSQL) { query1 = (char*)"INSERT INTO history_pgsql_query_digest VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)"; query32s = "INSERT INTO history_pgsql_query_digest VALUES " + generate_multi_rows_query(32, 15); } query32 = (char *)query32s.c_str(); rc = sdb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, sdb); rc = sdb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, sdb); int row_idx=0; int max_bulk_row_idx=r/32; max_bulk_row_idx=max_bulk_row_idx*32; query_digest_stats_pointers_t qdsp; time_t __now; time(&__now); unsigned long long curtime=monotonic_time(); time_t seen_time; for (std::unordered_map::iterator it=uqd.begin(); it!=uqd.end(); ++it) { QP_query_digest_stats * qds = (QP_query_digest_stats *)it->second; int idx=row_idx%32; if (row_idxhid); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*15)+3, qds->schemaname, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*15)+4, qds->username, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*15)+5, qds->client_address, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); sprintf(qdsp.digest,"0x%016llX", (long long unsigned int)qds->digest); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*15)+6, qdsp.digest, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); if (qds->digest_text) { rc=(*proxy_sqlite3_bind_text)(statement32, (idx*15)+7, qds->digest_text, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); } else { std::unordered_map::iterator it2; it2=uqdt.find(qds->digest); if (it2 != uqdt.end()) { rc=(*proxy_sqlite3_bind_text)(statement32, (idx*15)+7, it2->second, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); } else { // LCOV_EXCL_START assert(0); // LCOV_EXCL_STOP } } rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*15)+8, qds->count_star); ASSERT_SQLITE_OK(rc, sdb); { seen_time = __now - curtime/1000000 + qds->first_seen/1000000; rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*15)+9, seen_time); ASSERT_SQLITE_OK(rc, sdb); } { seen_time = __now - curtime/1000000 + qds->last_seen/1000000; rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*15)+10, seen_time); ASSERT_SQLITE_OK(rc, sdb); } rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*15)+11, qds->sum_time); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*15)+12, qds->min_time); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*15)+13, qds->max_time); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*15)+14, qds->rows_affected); ASSERT_SQLITE_OK(rc, sdb); // rows affected rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*15)+15, qds->rows_sent); ASSERT_SQLITE_OK(rc, sdb); // rows sent if (idx==31) { SAFE_SQLITE3_STEP2(statement32); rc=(*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, sdb); if (row_idx%100==0) { sdb->execute("COMMIT"); sdb->execute("BEGIN"); } } } else { // single row rc=(*proxy_sqlite3_bind_int64)(statement1, 1, __now); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_int64)(statement1, 2, qds->hid); ASSERT_SQLITE_OK(rc, sdb); assert(qds->schemaname); rc=(*proxy_sqlite3_bind_text)(statement1, 3, qds->schemaname, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, qds->username, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_text)(statement1, 5, qds->client_address, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); sprintf(qdsp.digest,"0x%016llX", (long long unsigned int)qds->digest); rc=(*proxy_sqlite3_bind_text)(statement1, 6, qdsp.digest, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); if (qds->digest_text) { rc=(*proxy_sqlite3_bind_text)(statement1, 7, qds->digest_text, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); } else { std::unordered_map::iterator it2; it2=uqdt.find(qds->digest); if (it2 != uqdt.end()) { rc=(*proxy_sqlite3_bind_text)(statement1, 7, it2->second, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, sdb); } else { // LCOV_EXCL_START assert(0); // LCOV_EXCL_STOP } } rc=(*proxy_sqlite3_bind_int64)(statement1, 8, qds->count_star); ASSERT_SQLITE_OK(rc, sdb); { seen_time = __now - curtime/1000000 + qds->first_seen/1000000; rc=(*proxy_sqlite3_bind_int64)(statement1, 9, seen_time); ASSERT_SQLITE_OK(rc, sdb); } { seen_time = __now - curtime/1000000 + qds->last_seen/1000000; rc=(*proxy_sqlite3_bind_int64)(statement1, 10, seen_time); ASSERT_SQLITE_OK(rc, sdb); } rc=(*proxy_sqlite3_bind_int64)(statement1, 11, qds->sum_time); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_int64)(statement1, 12, qds->min_time); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_int64)(statement1, 13, qds->max_time); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_bind_int64)(statement1, 14, qds->rows_affected); ASSERT_SQLITE_OK(rc, sdb); // rows affected rc=(*proxy_sqlite3_bind_int64)(statement1, 15, qds->rows_sent); ASSERT_SQLITE_OK(rc, sdb); // rows sent SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, sdb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, sdb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); sdb->execute("COMMIT"); for (std::unordered_map::iterator it=uqd.begin(); it!=uqd.end(); ++it) { QP_query_digest_stats * qds = (QP_query_digest_stats *)it->second; delete qds; } uqd.erase(uqd.begin(),uqd.end()); for (std::unordered_map::iterator it=uqdt.begin(); it!=uqdt.end(); ++it) { free(it->second); } uqdt.erase(uqdt.begin(),uqdt.end()); return r; } #include "Admin_ifaces.h" admin_main_loop_listeners S_amll; void flush_logs_handler() { GloAdmin->flush_logs(); } void ProxySQL_Admin::flush_logs() { if (GloMyLogger) { GloMyLogger->flush_log(); } if (GloPgSQL_Logger) { GloPgSQL_Logger->flush_log(); } this->flush_error_log(); proxysql_keylog_close(); char* ssl_keylog_file = this->get_variable((char*)"ssl_keylog_file"); if (ssl_keylog_file != NULL) { if (strlen(ssl_keylog_file) > 0) { if (proxysql_keylog_open(ssl_keylog_file) == false) { // re-opening file failed, setting ssl_keylog_enabled to false GloVars.global.ssl_keylog_enabled = false; proxy_warning("Cannot open SSLKEYLOGFILE '%s' for writing.\n", ssl_keylog_file); } } free(ssl_keylog_file); } proxy_debug(PROXY_DEBUG_ADMIN, 1, "Running PROXYSQL FLUSH LOGS\n"); } // Explicitly instantiate the required template class and member functions // NOTE: send_ok_msg_to_client and send_error_msg_to_client instantiations moved to after definitions (near line 5730) template int ProxySQL_Admin::FlushDigestTableToDisk<(SERVER_TYPE)0>(SQLite3DB*); template int ProxySQL_Admin::FlushDigestTableToDisk<(SERVER_TYPE)1>(SQLite3DB*); void ProxySQL_Admin::flush_configdb() { // see #923 wrlock(); admindb->execute((char *)"DETACH DATABASE disk"); delete configdb; configdb=new SQLite3DB(); if (access(GloVars.admindb, F_OK) == 0) { if (access(GloVars.admindb, W_OK) != 0) { proxy_error("Database file '%s' exists but is not writable\n", GloVars.admindb); exit(EXIT_SUCCESS); } } 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 synchronous=0"); wrunlock(); } bool ProxySQL_Admin::GenericRefreshStatistics(const char *query_no_space, unsigned int query_no_space_length, bool admin) { bool ret=false; bool refresh=false; bool stats_mysql_processlist=false; bool stats_pgsql_processlist=false; bool stats_mysql_free_connections=false; bool stats_pgsql_free_connections=false; bool stats_mysql_connection_pool=false; bool stats_mysql_connection_pool_reset=false; bool stats_mysql_query_digest=false; bool stats_pgsql_query_digest = false; bool stats_mysql_query_digest_reset=false; bool stats_pgsql_query_digest_reset = false; bool stats_mysql_errors=false; bool stats_mysql_errors_reset=false; bool stats_pgsql_errors = false; bool stats_pgsql_errors_reset = false; bool stats_mysql_global=false; bool stats_memory_metrics=false; bool stats_mysql_commands_counters=false; bool stats_pgsql_commands_counters = false; bool stats_mysql_query_rules=false; bool stats_pgsql_query_rules = false; bool stats_mysql_users=false; bool stats_pgsql_users = false; bool stats_mysql_gtid_executed=false; bool stats_mysql_client_host_cache=false; bool stats_mysql_client_host_cache_reset=false; bool stats_pgsql_client_host_cache = false; bool stats_pgsql_client_host_cache_reset = false; bool dump_global_variables=false; bool runtime_scheduler=false; bool runtime_restapi_routes=false; bool runtime_mysql_users=false; bool runtime_mysql_firewall=false; bool runtime_mysql_ldap_mapping=false; bool runtime_mysql_servers=false; bool runtime_mysql_query_rules=false; bool runtime_mysql_query_rules_fast_routing=false; bool runtime_pgsql_users = false; bool runtime_pgsql_firewall = false; bool runtime_pgsql_ldap_mapping = false; bool runtime_pgsql_servers = false; bool runtime_pgsql_query_rules = false; bool runtime_pgsql_query_rules_fast_routing = false; bool stats_pgsql_global = false; bool stats_pgsql_connection_pool = false; bool stats_pgsql_connection_pool_reset = false; bool runtime_proxysql_servers=false; bool runtime_checksums_values=false; bool runtime_coredump_filters=false; bool stats_mysql_prepared_statements_info = false; bool stats_pgsql_prepared_statements_info = false; #ifdef PROXYSQLCLICKHOUSE bool runtime_clickhouse_users = false; #endif /* PROXYSQLCLICKHOUSE */ bool monitor_mysql_server_group_replication_log=false; bool monitor_mysql_server_galera_log=false; bool monitor_mysql_server_aws_aurora_log=false; bool monitor_mysql_server_aws_aurora_check_status=false; bool stats_proxysql_servers_checksums = false; bool stats_proxysql_servers_metrics = false; bool stats_proxysql_message_metrics = false; bool stats_proxysql_message_metrics_reset = false; //bool stats_proxysql_servers_status = false; // temporary disabled because not implemented if (strcasestr(query_no_space, "pgsql processlist") || strcasestr(query_no_space, "pgsql activity") || strcasestr(query_no_space, "stats_pgsql_processlist") || strcasestr(query_no_space, "stats_pgsql_stat_activity")) // This will match the following usecases: // SHOW PGSQL PROCESSLIST // SHOW FULL PGSQL PROCESSLIST // SHOW PGSQL ACTIVITY // SHOW FULL PGSQL ACTIVITY // SELECT * FROM stats_pgsql_processlist // SELECT * FROM stats_pgsql_stat_activity { stats_pgsql_processlist = true; refresh = true; } else 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_pgsql_query_digest")) { stats_pgsql_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_pgsql_query_digest_reset")) { stats_pgsql_query_digest_reset = true; refresh = true; } if (stats_mysql_query_digest_reset == true && stats_mysql_query_digest == true) { int nd = 0; int ndr= 0; char *c = NULL; char *_ret = NULL; c = (char *)query_no_space; _ret = NULL; while ((_ret = strstr(c,"stats_mysql_query_digest_reset"))) { ndr++; c = _ret + strlen("stats_mysql_query_digest_reset"); } c = (char *)query_no_space; _ret = NULL; while ((_ret = strstr(c,"stats_mysql_query_digest"))) { nd++; c = _ret + strlen("stats_mysql_query_digest"); } if (nd == ndr) { stats_mysql_query_digest = false; } } if (stats_pgsql_query_digest_reset == true && stats_pgsql_query_digest == true) { int nd = 0; int ndr = 0; char* c = NULL; char* _ret = NULL; c=(char*)query_no_space; _ret=NULL; while ((_ret=strstr(c,"stats_pgsql_query_digest_reset"))) { ndr++; c = _ret+strlen("stats_pgsql_query_digest_reset"); } c=(char*)query_no_space; _ret = NULL; while ((_ret=strstr(c,"stats_pgsql_query_digest"))) { nd++; c = _ret+strlen("stats_pgsql_query_digest"); } if (nd==ndr) { stats_pgsql_query_digest = false; } } if (strstr(query_no_space,"stats_mysql_errors")) { stats_mysql_errors=true; refresh=true; } if (strstr(query_no_space,"stats_mysql_errors_reset")) { stats_mysql_errors_reset=true; refresh=true; } if (strstr(query_no_space, "stats_pgsql_errors")) { stats_pgsql_errors = true; refresh = true; } if (strstr(query_no_space, "stats_pgsql_errors_reset")) { stats_pgsql_errors_reset = true; refresh = true; } if (strstr(query_no_space,"stats_mysql_global")) { stats_mysql_global=true; refresh=true; } if (strstr(query_no_space, "stats_pgsql_global")) { stats_pgsql_global = true; refresh = true; } if (strstr(query_no_space,"stats_memory_metrics")) { stats_memory_metrics=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_pgsql_connection_pool_reset")) { stats_pgsql_connection_pool_reset = true; refresh = true; } else { if (strstr(query_no_space, "stats_pgsql_connection_pool")) { stats_pgsql_connection_pool = true; refresh = true; } } if (strstr(query_no_space,"stats_mysql_free_connections")) { stats_mysql_free_connections=true; refresh=true; } if (strstr(query_no_space, "stats_pgsql_free_connections")) { stats_pgsql_free_connections=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_pgsql_commands_counters")) { stats_pgsql_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_pgsql_query_rules")) { stats_pgsql_query_rules = true; refresh = true; } if (strstr(query_no_space,"stats_mysql_users")) { stats_mysql_users=true; refresh=true; } if (strstr(query_no_space,"stats_pgsql_users")) { stats_pgsql_users = true; refresh = true; } if (strstr(query_no_space,"stats_mysql_gtid_executed")) { stats_mysql_gtid_executed=true; refresh=true; } if (strstr(query_no_space,"stats_mysql_client_host_cache")) { stats_mysql_client_host_cache=true; refresh=true; } if (strstr(query_no_space,"stats_mysql_client_host_cache_reset")) { stats_mysql_client_host_cache_reset=true; refresh=true; } if (strstr(query_no_space, "stats_pgsql_client_host_cache")) { stats_pgsql_client_host_cache = true; refresh = true; } if (strstr(query_no_space, "stats_pgsql_client_host_cache_reset")) { stats_pgsql_client_host_cache_reset = true; refresh = true; } if (strstr(query_no_space,"stats_proxysql_servers_checksums")) { stats_proxysql_servers_checksums = true; refresh = true; } if (strstr(query_no_space,"stats_proxysql_servers_metrics")) { stats_proxysql_servers_metrics = true; refresh = true; } if (strstr(query_no_space,"stats_proxysql_message_metrics")) { stats_proxysql_message_metrics=true; refresh=true; } if (strstr(query_no_space,"stats_proxysql_message_metrics_reset")) { stats_proxysql_message_metrics_reset=true; refresh=true; } // temporary disabled because not implemented /* if (strstr(query_no_space,"stats_proxysql_servers_status")) { stats_proxysql_servers_status = true; refresh = true; } */ if (strstr(query_no_space,"stats_mysql_prepared_statements_info")) { stats_mysql_prepared_statements_info=true; refresh=true; } if (strstr(query_no_space, "stats_pgsql_prepared_statements_info")) { stats_pgsql_prepared_statements_info = 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") || strstr(query_no_space,"runtime_mysql_galera_hostgroups") || strstr(query_no_space,"runtime_mysql_aws_aurora_hostgroups") || strstr(query_no_space,"runtime_mysql_hostgroup_attributes") || strstr(query_no_space,"runtime_mysql_servers_ssl_params") ) { runtime_mysql_servers=true; refresh=true; } if ( strstr(query_no_space, "runtime_pgsql_servers") || strstr(query_no_space, "runtime_pgsql_replication_hostgroups") || strstr(query_no_space, "runtime_pgsql_hostgroup_attributes") ) { runtime_pgsql_servers = true; refresh = true; } if ( strstr(query_no_space,"runtime_mysql_firewall_whitelist_rules") || strstr(query_no_space,"runtime_mysql_firewall_whitelist_users") || strstr(query_no_space,"runtime_mysql_firewall_whitelist_sqli_fingerprints") ) { runtime_mysql_firewall=true; refresh=true; } if ( strstr(query_no_space, "runtime_pgsql_firewall_whitelist_rules") || strstr(query_no_space, "runtime_pgsql_firewall_whitelist_users") || strstr(query_no_space, "runtime_pgsql_firewall_whitelist_sqli_fingerprints") ) { runtime_pgsql_firewall = true; refresh = true; } if (strstr(query_no_space,"runtime_mysql_users")) { runtime_mysql_users=true; refresh=true; } if (strstr(query_no_space, "runtime_pgsql_users")) { runtime_pgsql_users = true; refresh = true; } if (GloMyLdapAuth) { if (strstr(query_no_space,"runtime_mysql_ldap_mapping")) { runtime_mysql_ldap_mapping=true; refresh=true; } if (strstr(query_no_space, "runtime_pgsql_ldap_mapping")) { runtime_mysql_ldap_mapping = 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_pgsql_query_rules")) { runtime_pgsql_query_rules = true; refresh = true; } if (strstr(query_no_space,"runtime_mysql_query_rules_fast_routing")) { runtime_mysql_query_rules_fast_routing=true; refresh=true; } if (strstr(query_no_space, "runtime_pgsql_query_rules_fast_routing")) { runtime_pgsql_query_rules_fast_routing = true; refresh = true; } if (strstr(query_no_space,"runtime_scheduler")) { runtime_scheduler=true; refresh=true; } if (strstr(query_no_space,"runtime_restapi_routes")) { runtime_restapi_routes=true; refresh=true; } if (strstr(query_no_space,"runtime_proxysql_servers")) { runtime_proxysql_servers=true; refresh=true; } if (strstr(query_no_space,"runtime_checksums_values")) { runtime_checksums_values=true; refresh=true; } if (strstr(query_no_space,"runtime_coredump_filters")) { runtime_coredump_filters=true; refresh=true; } #ifdef PROXYSQLCLICKHOUSE if (( GloVars.global.clickhouse_server == true ) && strstr(query_no_space,"runtime_clickhouse_users")) { runtime_clickhouse_users=true; refresh=true; } #endif /* PROXYSQLCLICKHOUSE */ } } if (strstr(query_no_space,"mysql_server_group_replication_log")) { monitor_mysql_server_group_replication_log=true; refresh=true; } if (strstr(query_no_space,"mysql_server_galera_log")) { monitor_mysql_server_galera_log=true; refresh=true; } if (strstr(query_no_space,"mysql_server_aws_aurora_log")) { monitor_mysql_server_aws_aurora_log=true; refresh=true; } if (strstr(query_no_space,"mysql_server_aws_aurora_check_status")) { monitor_mysql_server_aws_aurora_check_status=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_pgsql_processlist) stats___pgsql_processlist(); if (stats_mysql_query_digest_reset) { stats___mysql_query_digests_v2(true, stats_mysql_query_digest, false); } else { if (stats_mysql_query_digest) { stats___mysql_query_digests_v2(false, false, false); } } if (stats_pgsql_query_digest_reset) { stats___pgsql_query_digests_v2(true, stats_pgsql_query_digest, false); } else { if (stats_pgsql_query_digest) { stats___pgsql_query_digests_v2(false, false, false); } } if (stats_mysql_errors) stats___mysql_errors(false); if (stats_mysql_errors_reset) { stats___mysql_errors(true); } if (stats_pgsql_errors) { stats___pgsql_errors(false); } if (stats_pgsql_errors_reset) { stats___pgsql_errors(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_pgsql_connection_pool_reset) { stats___pgsql_connection_pool(true); } else { if (stats_pgsql_connection_pool) stats___pgsql_connection_pool(false); } if (stats_mysql_free_connections) stats___mysql_free_connections(); if (stats_pgsql_free_connections) stats___pgsql_free_connections(); if (stats_mysql_global) stats___mysql_global(); if (stats_pgsql_global) stats___pgsql_global(); if (stats_memory_metrics) stats___memory_metrics(); if (stats_mysql_query_rules) stats___mysql_query_rules(); if (stats_pgsql_query_rules) stats___pgsql_query_rules(); if (stats_mysql_commands_counters) stats___mysql_commands_counters(); if (stats_pgsql_commands_counters) stats___pgsql_commands_counters(); if (stats_mysql_users) stats___mysql_users(); if (stats_pgsql_users) stats___pgsql_users(); if (stats_mysql_gtid_executed) stats___mysql_gtid_executed(); // cluster if (stats_proxysql_servers_metrics) { stats___proxysql_servers_metrics(); } if (stats_proxysql_servers_checksums) { stats___proxysql_servers_checksums(); } if (stats_proxysql_message_metrics_reset) { stats___proxysql_message_metrics(true); } else { if (stats_proxysql_message_metrics) { stats___proxysql_message_metrics(false); } } // temporary disabled because not implemented // if (stats_proxysql_servers_status) { // stats___proxysql_servers_status(); // } if (stats_mysql_prepared_statements_info) { stats___mysql_prepared_statements_info(); } if (stats_pgsql_prepared_statements_info) { stats___pgsql_prepared_statements_info(); } if (stats_mysql_client_host_cache) { stats___mysql_client_host_cache(false); } if (stats_mysql_client_host_cache_reset) { stats___mysql_client_host_cache(true); } if (stats_pgsql_client_host_cache) { stats___pgsql_client_host_cache(false); } if (stats_pgsql_client_host_cache_reset) { stats___pgsql_client_host_cache(true); } if (admin) { if (dump_global_variables) { pthread_mutex_lock(&GloVars.checksum_mutex); 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); #ifdef PROXYSQLCLICKHOUSE flush_clickhouse_variables___runtime_to_database(admindb, false, false, false, true); #endif /* PROXYSQLCLICKHOUSE */ flush_sqliteserver_variables___runtime_to_database(admindb, false, false, false, true); flush_ldap_variables___runtime_to_database(admindb, false, false, false, true); flush_pgsql_variables___runtime_to_database(admindb, false, false, false, true); flush_mcp_variables___runtime_to_database(admindb, false, false, false, true, false); flush_genai_variables___runtime_to_database(admindb, false, false, false, true, false); pthread_mutex_unlock(&GloVars.checksum_mutex); } if (runtime_mysql_servers) { int old_hostgroup_manager_verbose = mysql_thread___hostgroup_manager_verbose; mysql_thread___hostgroup_manager_verbose = 0; mysql_servers_wrlock(); save_mysql_servers_runtime_to_database(true); mysql_servers_wrunlock(); mysql_thread___hostgroup_manager_verbose = old_hostgroup_manager_verbose; } if (runtime_pgsql_servers) { int old_hostgroup_manager_verbose = pgsql_thread___hostgroup_manager_verbose; pgsql_thread___hostgroup_manager_verbose = 0; pgsql_servers_wrlock(); save_pgsql_servers_runtime_to_database(true); pgsql_servers_wrunlock(); pgsql_thread___hostgroup_manager_verbose = old_hostgroup_manager_verbose; } if (runtime_proxysql_servers) { //mysql_servers_wrlock(); // before save_proxysql_servers_runtime_to_database() we release // sql_query_global_mutex to prevent a possible deadlock due to // a race condition // save_proxysql_servers_runtime_to_database() calls ProxySQL_Cluster::dump_table_proxysql_servers() pthread_mutex_unlock(&SPA->sql_query_global_mutex); save_proxysql_servers_runtime_to_database(true); pthread_mutex_lock(&SPA->sql_query_global_mutex); //mysql_servers_wrunlock(); } if (runtime_mysql_users) { save_mysql_users_runtime_to_database(true); } if (runtime_pgsql_users) { save_pgsql_users_runtime_to_database(true); } if (runtime_mysql_firewall) { save_mysql_firewall_from_runtime(true); } if (runtime_pgsql_firewall) { save_pgsql_firewall_from_runtime(true); } if (runtime_mysql_ldap_mapping) { save_mysql_ldap_mapping_runtime_to_database(true); } if (runtime_pgsql_ldap_mapping) { save_pgsql_ldap_mapping_runtime_to_database(true); } if (runtime_mysql_query_rules) { save_mysql_query_rules_from_runtime(true); } if (runtime_pgsql_query_rules) { save_pgsql_query_rules_from_runtime(true); } if (runtime_mysql_query_rules_fast_routing) { save_mysql_query_rules_fast_routing_from_runtime(true); } if (runtime_pgsql_query_rules_fast_routing) { save_pgsql_query_rules_fast_routing_from_runtime(true); } if (runtime_scheduler) { save_scheduler_runtime_to_database(true); } if (runtime_restapi_routes) { proxysql_restapi().save_restapi_runtime_to_database(true); } if (runtime_checksums_values) { dump_checksums_values_table(); } if (runtime_coredump_filters) { dump_coredump_filter_values_table(); } #ifdef PROXYSQLCLICKHOUSE if (runtime_clickhouse_users) { save_clickhouse_users_runtime_to_database(true); } #endif /* PROXYSQLCLICKHOUSE */ } if (monitor_mysql_server_group_replication_log) { if (GloMyMon) { GloMyMon->populate_monitor_mysql_server_group_replication_log(); } } if (monitor_mysql_server_galera_log) { if (GloMyMon) { GloMyMon->populate_monitor_mysql_server_galera_log(); } } if (monitor_mysql_server_aws_aurora_log) { if (GloMyMon) { GloMyMon->populate_monitor_mysql_server_aws_aurora_log(); } } if (monitor_mysql_server_aws_aurora_check_status) { if (GloMyMon) { GloMyMon->populate_monitor_mysql_server_aws_aurora_check_status(); } } //pthread_mutex_unlock(&admin_mutex); } int freelist_count = statsdb->return_one_int("PRAGMA freelist_count"); if (freelist_count < 1000) { ret = false; } else { int page_count = statsdb->return_one_int("PRAGMA page_count"); ret = (freelist_count * 100 / page_count) > 20; #ifdef DEBUG if (ret) { proxy_debug(PROXY_DEBUG_ADMIN, 4, "VACUUM required for 'stats_db' page_count=%d freelist_count=%d\n", page_count, freelist_count ); } #endif } return ret; } 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) + 1); 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(q2); free(tn); return NULL; } if (resultset->rows_count==0) { free(q2); 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[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[1]; pta[2]=(char *)"YES"; if (r->fields[3]) { if (strcmp(r->fields[3],"1")==0) { pta[2]=(char *)"NO"; } } pta[3]=(char *)""; if (r->fields[5]) { if (strcmp(r->fields[5],"0")) { pta[3]=(char *)"PRI"; } } 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)+1); 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(q2); free(tn); return NULL; } if (resultset->rows_count==0) { free(q2); 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"; delete resultset; sprintf(q2,"SELECT COUNT(*) FROM %s",tn); admindb->execute_statement(q2, &error , &cols , &affected_rows , &resultset); char buf[20]; sprintf(buf,"%d",resultset->rows_count); pta[4]=buf; delete resultset; free(q2); 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; } template void admin_session_handler(S* sess, void *_pa, PtrSize_t *pkt); /** * @brief Delete all rows from statistics tables and vacuum the database. * * This function is called when `TRUNCATE` commands are executed on statistics * tables via the Admin interface. It performs two operations: * 1. Deletes all rows from a predefined list of statistics tables (and their * `*_reset` counterparts). * 2. Executes `VACUUM` on the statistics database to reclaim space. * * The function respects the `variables.vacuum_stats` setting: if `false`, * the function returns immediately without performing any operation. * * @param is_admin If `true`, operate on the `stats` schema within the admin * database (`stats.*` tables). If `false`, operate on the * standalone statistics database. * * @note The list of tables includes both MySQL and PostgreSQL statistics * tables, even when the trigger is a MySQL-specific `TRUNCATE`. This * ensures statistics are fully cleared regardless of the protocol that * initiated the operation. * * @warning The table `stats_pgsql_stat_activity` is explicitly excluded from * the deletion list because it is defined as a SQL VIEW (see * `STATS_SQLITE_TABLE_PGSQL_STAT_ACTIVITY`). Attempting to `DELETE` * from a view would cause a SQLite error: * `"cannot modify stats_pgsql_stat_activity because it is a view"`. * The view is based on `stats_pgsql_processlist`; clearing the * underlying table automatically clears the view's content. */ void ProxySQL_Admin::vacuum_stats(bool is_admin) { if (variables.vacuum_stats==false) { return; } const vector tablenames = { "stats_mysql_commands_counters", "stats_pgsql_commands_counters", "stats_mysql_free_connections", "stats_pgsql_free_connections", "stats_mysql_connection_pool", "stats_mysql_connection_pool_reset", "stats_pgsql_connection_pool", "stats_pgsql_connection_pool_reset", "stats_mysql_prepared_statements_info", "stats_pgsql_prepared_statements_info", "stats_mysql_processlist", "stats_pgsql_processlist", //"stats_pgsql_stat_activity", // VIEW, not a table; DELETE would fail "stats_mysql_query_digest", "stats_mysql_query_digest_reset", "stats_pgsql_query_digest", "stats_pgsql_query_digest_reset", "stats_mysql_query_rules", "stats_pgsql_query_rules", "stats_mysql_users", "stats_pgsql_users", "stats_proxysql_servers_checksums", "stats_proxysql_servers_metrics", "stats_proxysql_servers_status", }; string s; SQLite3DB *tmpdb = NULL; if (is_admin == true) { tmpdb = admindb; } else { tmpdb = statsdb; } for (auto it = tablenames.begin(); it != tablenames.end(); it++) { s = "DELETE FROM "; if (is_admin == true) s+= "stats."; s += *it; tmpdb->execute(s.c_str()); } s = "VACUUM"; if (is_admin == true) s+= " stats"; tmpdb->execute(s.c_str()); } void *child_mysql(void *arg) { if (GloMTH == nullptr) { return NULL; } pthread_attr_t thread_attr; size_t tmp_stack_size=0; if (!pthread_attr_init(&thread_attr)) { if (!pthread_attr_getstacksize(&thread_attr , &tmp_stack_size )) { __sync_fetch_and_add(&GloVars.statuses.stack_memory_admin_threads,tmp_stack_size); } } arg_proxysql_adm*myarg = (arg_proxysql_adm*)arg; int client = myarg->client_t; //struct sockaddr *addr = arg->addr; //socklen_t addr_size; 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(); GloMyQPro->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_ADMIN; sess->handler_function=admin_session_handler; MySQL_Data_Stream *myds=sess->client_myds; sess->start_time=mysql_thr->curtime; sess->client_myds->client_addrlen=myarg->addr_size; sess->client_myds->client_addr=myarg->addr; switch (sess->client_myds->client_addr->sa_family) { case AF_INET: { struct sockaddr_in *ipv4 = (struct sockaddr_in *)sess->client_myds->client_addr; char buf[INET_ADDRSTRLEN]; inet_ntop(sess->client_myds->client_addr->sa_family, &ipv4->sin_addr, buf, INET_ADDRSTRLEN); sess->client_myds->addr.addr = strdup(buf); sess->client_myds->addr.port = htons(ipv4->sin_port); break; } case AF_INET6: { struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)sess->client_myds->client_addr; char buf[INET6_ADDRSTRLEN]; inet_ntop(sess->client_myds->client_addr->sa_family, &ipv6->sin6_addr, buf, INET6_ADDRSTRLEN); sess->client_myds->addr.addr = strdup(buf); sess->client_myds->addr.port = htons(ipv6->sin6_port); break; } default: sess->client_myds->addr.addr = strdup("localhost"); break; } fds[0].fd=client; fds[0].revents=0; fds[0].events=POLLIN|POLLOUT; //free(arg->addr); // do not free free(arg); sess->client_myds->myprot.generate_pkt_initial_handshake(true,NULL,NULL, &sess->thread_session_id, false); 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(&__admin_refresh_interval,0)); if (rc == -1) { if (errno == EINTR) { continue; } else { goto __exit_child_mysql; } } mysql_thr->curtime = monotonic_time(); myds->revents=fds[0].revents; int rb = 0; rb = myds->read_from_net(); if (myds->net_failure) goto __exit_child_mysql; myds->read_pkts(); if (myds->encrypted == true) { // PMC-10004 // we probably should use SSL_pending() and/or SSL_has_pending() to determine // if there is more data to be read, but it doesn't seem to be working. // Therefore we try to call read_from_net() again as long as there is data. // Previously we hardcoded 16KB but it seems that it can return in smaller // chunks of 4KB. // We finally removed the chunk size as it seems that any size is possible. while (rb > 0) { rb = 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; __sync_fetch_and_sub(&GloVars.statuses.stack_memory_admin_threads,tmp_stack_size); return NULL; } void* child_postgres(void* arg) { if (GloPTH == nullptr) { return NULL; } pthread_attr_t thread_attr; size_t tmp_stack_size = 0; if (!pthread_attr_init(&thread_attr)) { if (!pthread_attr_getstacksize(&thread_attr, &tmp_stack_size)) { __sync_fetch_and_add(&GloVars.statuses.stack_memory_admin_threads, tmp_stack_size); } } arg_proxysql_adm* myarg = (arg_proxysql_adm*)arg; int client = myarg->client_t; struct pollfd fds[1]; nfds_t nfds = 1; int rc; pthread_mutex_unlock(&sock_mutex); PgSQL_Thread* pgsql_thr = new PgSQL_Thread(); pgsql_thr->curtime = monotonic_time(); GloPgQPro->init_thread(); pgsql_thr->refresh_variables(); PgSQL_Session* sess = pgsql_thr->create_new_session_and_client_data_stream(client); sess->thread = pgsql_thr; sess->session_type = PROXYSQL_SESSION_ADMIN; sess->handler_function=admin_session_handler; PgSQL_Data_Stream* myds = sess->client_myds; sess->start_time = pgsql_thr->curtime; sess->client_myds->client_addrlen = myarg->addr_size; sess->client_myds->client_addr = myarg->addr; switch (sess->client_myds->client_addr->sa_family) { case AF_INET: { struct sockaddr_in* ipv4 = (struct sockaddr_in*)sess->client_myds->client_addr; char buf[INET_ADDRSTRLEN]; inet_ntop(sess->client_myds->client_addr->sa_family, &ipv4->sin_addr, buf, INET_ADDRSTRLEN); sess->client_myds->addr.addr = strdup(buf); sess->client_myds->addr.port = htons(ipv4->sin_port); break; } case AF_INET6: { struct sockaddr_in6* ipv6 = (struct sockaddr_in6*)sess->client_myds->client_addr; char buf[INET6_ADDRSTRLEN]; inet_ntop(sess->client_myds->client_addr->sa_family, &ipv6->sin6_addr, buf, INET6_ADDRSTRLEN); sess->client_myds->addr.addr = strdup(buf); sess->client_myds->addr.port = htons(ipv6->sin6_port); break; } default: sess->client_myds->addr.addr = strdup("localhost"); break; } fds[0].fd = client; fds[0].revents = 0; fds[0].events = POLLIN | POLLOUT; //free(arg->addr); // do not free free(arg); myds->DSS = STATE_SERVER_HANDSHAKE; sess->status = CONNECTING_CLIENT; 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(&__admin_refresh_interval, 0)); if (rc == -1) { if (errno == EINTR) { continue; } else { goto __exit_child_postgres; } } pgsql_thr->curtime = monotonic_time(); myds->revents = fds[0].revents; int rb = 0; rb = myds->read_from_net(); if (myds->net_failure) goto __exit_child_postgres; myds->read_pkts(); if (myds->encrypted == true) { // PMC-10004 // we probably should use SSL_pending() and/or SSL_has_pending() to determine // if there is more data to be read, but it doesn't seem to be working. // Therefore we try to call read_from_net() again as long as there is data. // Previously we hardcoded 16KB but it seems that it can return in smaller // chunks of 4KB. // We finally removed the chunk size as it seems that any size is possible. while (rb > 0) { rb = myds->read_from_net(); if (myds->net_failure) goto __exit_child_postgres; myds->read_pkts(); } } sess->to_process = 1; int rc = sess->handler(); if (rc == -1) goto __exit_child_postgres; } __exit_child_postgres: delete pgsql_thr; __sync_fetch_and_sub(&GloVars.statuses.stack_memory_admin_threads, tmp_stack_size); 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; } */ void * admin_main_loop(void *arg) { int i; int rc; int version=0; 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_ADMIN_LISTENERS]; set_thread_name("Admin", GloVars.set_thread_name); 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 ((admin_nostart_ && __sync_val_compare_and_swap(&GloVars.global.nostart,0,1)==0) || __sync_fetch_and_add(&glovars.shutdown,0)==1) { admin_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;iaddr=(struct sockaddr *)malloc(sizeof(custom_sockaddr)); passarg->addr_size = sizeof(custom_sockaddr); memset(passarg->addr, 0, sizeof(custom_sockaddr)); passarg->client_t = accept(fds[i].fd, (struct sockaddr*)passarg->addr, &passarg->addr_size); // printf("Connected: %s:%d sock=%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), client_t); pthread_attr_getstacksize (&attr, &stacks); // printf("Default stack size = %d\n", stacks); pthread_mutex_lock (&sock_mutex); //client=(int *)malloc(sizeof(int)); //*client= client_t; //if ( pthread_create(&child, &attr, child_func[callback_func[i]], client) != 0 ) { if ( pthread_create(&child, &attr, child_func[callback_func[i]], passarg) != 0 ) { // LCOV_EXCL_START perror("pthread_create"); proxy_error("Thread creation\n"); assert(0); // LCOV_EXCL_STOP } } fds[i].revents=0; } __end_while_pool: { if (GloProxyStats->MySQL_Threads_Handler_timetoget(curtime)) { if (GloMTH) { SQLite3_result * resultset=GloMTH->SQL3_GlobalStatus(false); if (resultset) { GloProxyStats->MySQL_Threads_Handler_sets(resultset); delete resultset; } } if (MyHGM) { SQLite3_result * resultset=MyHGM->SQL3_Get_ConnPool_Stats(); if (resultset) { SQLite3_result * resultset2 = NULL; // In debug, run the code to generate metrics so that it can be tested even if the web interface plugin isn't loaded. #ifdef DEBUG if (true) { #else if (GloVars.web_interface_plugin) { #endif resultset2 = MyHGM->SQL3_Connection_Pool(false); } GloProxyStats->MyHGM_Handler_sets(resultset, resultset2); delete resultset; if (resultset2) { delete resultset2; } } } } if (GloProxyStats->MySQL_Query_Cache_timetoget(curtime)) { if (GloMyQC) { SQLite3_result * resultset=GloMyQC->SQL3_getStats(); if (resultset) { GloProxyStats->MySQL_Query_Cache_sets(resultset); delete resultset; } } } if (GloProxyStats->mysql_query_digest_to_disk_timetoget(curtime)) { unsigned long long curtime1=monotonic_time(); int r1 = SPA->FlushDigestTableToDisk(SPA->statsdb_disk); unsigned long long curtime2=monotonic_time(); curtime1 = curtime1/1000; curtime2 = curtime2/1000; proxy_info("Automatically saved stats_mysql_query_digest to disk: %llums to write %d entries\n", curtime2-curtime1, r1); } if (GloProxyStats->system_cpu_timetoget(curtime)) { GloProxyStats->system_cpu_sets(); } #ifndef NOJEM if (GloProxyStats->system_memory_timetoget(curtime)) { GloProxyStats->system_memory_sets(); } #endif } if (S_amll.get_version()!=version) { S_amll.wrlock(); version=S_amll.get_version(); 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); bool is_ipv6 = false; char *h = NULL; if (*sn == '[') { is_ipv6 = true; 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); } #ifdef SO_REUSEPORT int s = ( atoi(port) ? listen_on_port(add, atoi(port), 128, true) : listen_on_unix(add, 128)); #else int s = ( atoi(port) ? listen_on_port(add, atoi(port), 128) : listen_on_unix(add, 128)); #endif //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 (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 (is_ipv6 == false) { if (add) free(add); if (port) free(port); } } i = 0; j = 0; for (; j < S_amll.ifaces_pgsql->ifaces->len; j++) { char* add = NULL; char* port = NULL; char* sn = (char*)S_amll.ifaces_pgsql->ifaces->index(j); bool is_ipv6 = false; char* h = NULL; if (*sn == '[') { is_ipv6 = true; 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); } #ifdef SO_REUSEPORT int s = (atoi(port) ? listen_on_port(add, atoi(port), 128, true) : listen_on_unix(add, 128)); #else int s = (atoi(port) ? listen_on_port(add, atoi(port), 128) : listen_on_unix(add, 128)); #endif //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 (s > 0) { fds[nfds].fd = s; fds[nfds].events = POLLIN; fds[nfds].revents = 0; callback_func[nfds] = 2; socket_names[nfds] = strdup(sn); nfds++; } if (is_ipv6 == false) { 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; ip_update_metrics(); } // Update mysql_hostgroups_manager metrics if (MyHGM) { MyHGM->p_update_metrics(); } // Update monitor metrics if (GloMyMon) { GloMyMon->p_update_metrics(); } // Update mysql query_cache metrics if (GloMyQC) { GloMyQC->p_update_metrics(); } #if 0 // Turning off Prometheus metrics collection for PostgreSQL modules in ProxySQL // Update pgsql_threads_handler metrics if (GloPTH) { GloPTH->p_update_metrics(); } // Update pgsql_hostgroups_manager metrics if (PgHGM) { PgHGM->p_update_metrics(); } // Update pgsql query_cache metrics if (GloPgQC) { GloPgQC->p_update_metrics(); } #endif // Update cluster metrics if (GloProxyCluster) { GloProxyCluster->p_update_metrics(); } // Update Logger metrics if (GloMyLogger) { GloMyLogger->p_update_metrics(); } // Update admin metrics GloAdmin->p_update_metrics(); } ProxySQL_Admin::ProxySQL_Admin() : serial_exposer(std::function { update_modules_metrics }) { #ifdef DEBUG debugdb_disk = NULL; if (glovars.has_debug==false) { #else if (glovars.has_debug==true) { #endif /* DEBUG */ perror("Incompatible debugging version"); exit(EXIT_FAILURE); } if (proxysql_version == NULL) { proxysql_version = strdup(PROXYSQL_VERSION); } SPA=this; //Initialize locker #ifdef PA_PTHREAD_MUTEX pthread_rwlock_init(&rwlock,NULL); #else spinlock_rwlock_init(&rwlock); #endif #ifdef PA_PTHREAD_MUTEX pthread_mutex_init(&mysql_servers_lock, NULL); #else spinlock_rwlock_init(&mysql_servers_rwlock); #endif #ifdef PA_PTHREAD_MUTEX pthread_mutex_init(&pgsql_servers_lock, NULL); #else spinlock_rwlock_init(&pgsql_servers_rwlock); #endif pthread_mutex_init(&sql_query_global_mutex, NULL); generate_load_save_disk_commands("mysql_firewall", "MYSQL FIREWALL"); generate_load_save_disk_commands("mysql_query_rules", "MYSQL QUERY RULES"); generate_load_save_disk_commands("mysql_users", "MYSQL USERS"); generate_load_save_disk_commands("mysql_servers", "MYSQL SERVERS"); generate_load_save_disk_commands("mysql_variables", "MYSQL VARIABLES"); generate_load_save_disk_commands("pgsql_firewall", "PGSQL FIREWALL"); generate_load_save_disk_commands("pgsql_query_rules", "PGSQL QUERY RULES"); generate_load_save_disk_commands("pgsql_users", "PGSQL USERS"); generate_load_save_disk_commands("pgsql_servers", "PGSQL SERVERS"); generate_load_save_disk_commands("pgsql_variables", "PGSQL VARIABLES"); generate_load_save_disk_commands("mcp_variables", "MCP VARIABLES"); generate_load_save_disk_commands("genai_variables", "GENAI VARIABLES"); generate_load_save_disk_commands("scheduler", "SCHEDULER"); generate_load_save_disk_commands("restapi", "RESTAPI"); generate_load_save_disk_commands("proxysql_servers", "PROXYSQL SERVERS"); { // we perform some sanity check assert(load_save_disk_commands.size() > 0); for (auto it = load_save_disk_commands.begin(); it != load_save_disk_commands.end(); it++) { vector& vec1 = get<1>(it->second); assert(vec1.size() == 3); vector& vec2 = get<2>(it->second); assert(vec2.size() == 3); } } variables.admin_credentials=strdup("admin:admin"); variables.stats_credentials=strdup("stats:stats"); if (GloVars.__cmd_proxysql_admin_socket) { variables.mysql_ifaces=strdup(GloVars.__cmd_proxysql_admin_socket); } else { variables.mysql_ifaces=strdup("0.0.0.0:6032"); // changed. See isseu #1103 } variables.pgsql_ifaces= strdup("0.0.0.0:6132"); variables.telnet_admin_ifaces=NULL; variables.telnet_stats_ifaces=NULL; variables.refresh_interval=2000; //variables.hash_passwords=true; // issue #676 variables.vacuum_stats=true; // issue #1011 variables.admin_read_only=false; // by default, the admin interface accepts writes variables.admin_version=(char *)PROXYSQL_VERSION; variables.cluster_username=strdup((char *)""); variables.cluster_password=strdup((char *)""); variables.cluster_check_interval_ms=1000; variables.cluster_check_status_frequency=10; variables.cluster_mysql_query_rules_diffs_before_sync = 3; variables.cluster_mysql_servers_diffs_before_sync = 3; variables.cluster_mysql_users_diffs_before_sync = 3; variables.cluster_proxysql_servers_diffs_before_sync = 3; variables.cluster_mysql_variables_diffs_before_sync = 3; variables.cluster_admin_variables_diffs_before_sync = 3; variables.cluster_ldap_variables_diffs_before_sync = 3; variables.cluster_mysql_servers_sync_algorithm = 1; checksum_variables.checksum_mysql_query_rules = true; checksum_variables.checksum_mysql_servers = true; checksum_variables.checksum_mysql_users = true; checksum_variables.checksum_mysql_variables = true; checksum_variables.checksum_admin_variables = true; checksum_variables.checksum_ldap_variables = true; variables.cluster_mysql_query_rules_save_to_disk = true; variables.cluster_mysql_servers_save_to_disk = true; variables.cluster_mysql_users_save_to_disk = true; variables.cluster_proxysql_servers_save_to_disk = true; variables.cluster_mysql_variables_save_to_disk = true; variables.cluster_admin_variables_save_to_disk = true; variables.cluster_ldap_variables_save_to_disk = true; variables.stats_mysql_connection_pool = 60; variables.stats_mysql_connections = 60; variables.stats_mysql_query_cache = 60; variables.stats_mysql_query_digest_to_disk = 0; variables.stats_mysql_eventslog_sync_buffer_to_disk = 0; variables.stats_system_cpu = 60; variables.stats_system_memory = 60; GloProxyStats->variables.stats_mysql_connection_pool = 60; GloProxyStats->variables.stats_mysql_connections = 60; GloProxyStats->variables.stats_mysql_query_cache = 60; GloProxyStats->variables.stats_mysql_query_digest_to_disk = 0; GloProxyStats->variables.stats_mysql_eventslog_sync_buffer_to_disk = 0; GloProxyStats->variables.stats_system_cpu = 60; #ifndef NOJEM GloProxyStats->variables.stats_system_memory = 60; #endif variables.restapi_enabled = false; variables.restapi_enabled_old = false; variables.restapi_port = 6070; variables.restapi_port_old = variables.restapi_port; variables.web_enabled = false; variables.web_enabled_old = false; variables.web_port = 6080; variables.web_port_old = variables.web_port; variables.web_verbosity = 0; variables.p_memory_metrics_interval = 61; all_modules_started = false; #ifdef DEBUG variables.debug=GloVars.global.gdbg; debug_output = 1; proxysql_set_admin_debug_output(debug_output); #endif /* DEBUG */ variables.coredump_generation_interval_ms = 30000; variables.coredump_generation_threshold = 10; variables.ssl_keylog_file = strdup(""); last_p_memory_metrics_ts = 0; // create the scheduler scheduler=new ProxySQL_External_Scheduler(); match_regexes.opt=(re2::RE2::Options *)new re2::RE2::Options(RE2::Quiet); re2::RE2::Options *opt2=(re2::RE2::Options *)match_regexes.opt; opt2->set_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); // Default initialize prometheus collectable flag registered_prometheus_collectable = false; // Initialize prometheus metrics init_prometheus_counter_array(admin_metrics_map, this->metrics.p_counter_array); init_prometheus_gauge_array(admin_metrics_map, this->metrics.p_gauge_array); init_prometheus_dyn_gauge_array(admin_metrics_map, this->metrics.p_dyn_gauge_array); // processlist configuration variables.mysql_processlist.show_extended = 0; variables.pgsql_processlist.show_extended = 0; variables.mysql_processlist.show_idle_session = true; variables.pgsql_processlist.show_idle_session = true; variables.mysql_processlist.max_query_length = PROCESSLIST_MAX_QUERY_LEN_DEFAULT; variables.pgsql_processlist.max_query_length = PROCESSLIST_MAX_QUERY_LEN_DEFAULT; // NOTE: Imposing fixed value to 'version_info' matching 'mysqld_exporter' this->metrics.p_gauge_array[p_admin_gauge::version_info]->Set(1); }; void ProxySQL_Admin::wrlock() { #ifdef PA_PTHREAD_MUTEX pthread_rwlock_wrlock(&rwlock); #else spin_wrlock(&rwlock); #endif }; void ProxySQL_Admin::wrunlock() { #ifdef PA_PTHREAD_MUTEX pthread_rwlock_unlock(&rwlock); #else spin_wrunlock(&rwlock); #endif }; void ProxySQL_Admin::mysql_servers_wrlock() { #ifdef PA_PTHREAD_MUTEX pthread_mutex_lock(&mysql_servers_lock); #else spin_wrlock(&mysql_servers_rwlock); #endif }; void ProxySQL_Admin::mysql_servers_wrunlock() { #ifdef PA_PTHREAD_MUTEX pthread_mutex_unlock(&mysql_servers_lock); #else spin_wrunlock(&mysql_servers_rwlock); #endif }; void ProxySQL_Admin::pgsql_servers_wrlock() { #ifdef PA_PTHREAD_MUTEX pthread_mutex_lock(&pgsql_servers_lock); #else spin_wrlock(&pgsql_servers_rwlock); #endif }; void ProxySQL_Admin::pgsql_servers_wrunlock() { #ifdef PA_PTHREAD_MUTEX pthread_mutex_unlock(&pgsql_servers_lock); #else spin_wrunlock(&pgsql_servers_rwlock); #endif }; void ProxySQL_Admin::print_version() { fprintf(stderr,"Standard ProxySQL Admin rev. %s -- %s -- %s\n", PROXYSQL_ADMIN_VERSION, __FILE__, __TIMESTAMP__); }; void ProxySQL_Admin::init_ldap() { if (GloMyLdapAuth) { insert_into_tables_defs(tables_defs_admin,"mysql_ldap_mapping", ADMIN_SQLITE_TABLE_MYSQL_LDAP_MAPPING); insert_into_tables_defs(tables_defs_admin,"runtime_mysql_ldap_mapping", ADMIN_SQLITE_TABLE_RUNTIME_MYSQL_LDAP_MAPPING); insert_into_tables_defs(tables_defs_config,"mysql_ldap_mapping", ADMIN_SQLITE_TABLE_MYSQL_LDAP_MAPPING); } } void ProxySQL_Admin::init_http_server() { AdminHTTPServer = new ProxySQL_HTTP_Server(); AdminHTTPServer->init(); AdminHTTPServer->print_version(); } #ifdef PROXYSQLCLICKHOUSE void ProxySQL_Admin::init_clickhouse_variables() { flush_clickhouse_variables___runtime_to_database(configdb, false, false, false); flush_clickhouse_variables___runtime_to_database(admindb, false, true, false); flush_clickhouse_variables___database_to_runtime(admindb,true); } #endif /* CLICKHOUSE */ void ProxySQL_Admin::init_sqliteserver_variables() { flush_sqliteserver_variables___runtime_to_database(configdb, false, false, false); flush_sqliteserver_variables___runtime_to_database(admindb, false, true, false); flush_sqliteserver_variables___database_to_runtime(admindb,true); } void ProxySQL_Admin::init_ldap_variables() { /* if (variables.hash_passwords==true) { proxy_info("Impossible to set admin-hash_passwords=true when LDAP is enabled. Reverting to false\n"); variables.hash_passwords=false; } */ flush_ldap_variables___runtime_to_database(configdb, false, false, false); flush_ldap_variables___runtime_to_database(admindb, false, true, false); flush_ldap_variables___database_to_runtime(admindb,true); admindb->execute((char *)"DETACH DATABASE disk"); check_and_build_standard_tables(admindb, tables_defs_admin); check_and_build_standard_tables(configdb, tables_defs_config); __attach_db(admindb, configdb, (char *)"disk"); admindb->execute("INSERT OR REPLACE INTO main.mysql_ldap_mapping SELECT * FROM disk.mysql_ldap_mapping"); } void ProxySQL_Admin::init_pgsql_variables() { flush_pgsql_variables___runtime_to_database(configdb, false, false, false); flush_pgsql_variables___runtime_to_database(admindb, false, true, false); flush_pgsql_variables___database_to_runtime(admindb, true); } void ProxySQL_Admin::init_mcp_variables() { if (GloMCPH) { flush_mcp_variables___runtime_to_database(configdb, false, false, false, false, false); flush_mcp_variables___runtime_to_database(admindb, false, true, false, false, false); flush_mcp_variables___database_to_runtime(admindb, true, "", 0); } } void ProxySQL_Admin::init_genai_variables() { flush_genai_variables___runtime_to_database(configdb, false, false, false); flush_genai_variables___runtime_to_database(admindb, false, true, false); flush_genai_variables___database_to_runtime(admindb, true); } void ProxySQL_Admin::admin_shutdown() { int i; // do { usleep(50); } while (main_shutdown==0); if (Admin_HTTP_Server) { if (variables.web_enabled) { MHD_stop_daemon(Admin_HTTP_Server); Admin_HTTP_Server = NULL; } } delete AdminHTTPServer; if (AdminRestApiServer) { delete AdminRestApiServer; AdminRestApiServer = NULL; } AdminHTTPServer = NULL; pthread_join(admin_thr, NULL); delete admindb; delete statsdb; delete configdb; delete monitordb; delete statsdb_disk; #ifdef DEBUG proxysql_set_admin_debugdb_disk(NULL); delete debugdb_disk; #endif (*proxy_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; } }; std::map request_headers(const httpserver::http_request& request) { auto req_headers = request.get_headers(); std::map result {}; for (const auto& header : req_headers) { result.insert({header.first, header.second}); } return result; } std::shared_ptr make_response( const std::pair, std::string>& res_data ) { std::shared_ptr response = std::make_shared(httpserver::string_response(res_data.second)); for (const auto& h_key_val : res_data.first) { response->with_header(h_key_val.first, h_key_val.second); } return response; } /** * @brief Checks if the supplied port is available. * * @param port_num The port number to check. * @param free Output parameter. True if the port is free, false otherwise. * * @return Returns: * - '-1' in case 'SO_REUSEADDR' fails to be set for the check. * - '-2' in case of invalid arguments supplied. * - '0' otherwise. */ int check_port_availability(int port_num, bool* port_free) { int ecode = 0; int sfd = 0; int reuseaddr = 1; struct sockaddr_in tmp_addr; if (port_num == 0 || port_free == nullptr) { return -2; } // set 'port_free' to false by default *port_free = false; sfd = socket(AF_INET, SOCK_STREAM, 0); memset(&tmp_addr, 0, sizeof(tmp_addr)); tmp_addr.sin_family = AF_INET; tmp_addr.sin_port = htons(port_num); tmp_addr.sin_addr.s_addr = INADDR_ANY; if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr, sizeof(reuseaddr)) == -1) { close(sfd); ecode = -1; } else { if (::bind(sfd, (struct sockaddr*)&tmp_addr, sizeof(tmp_addr)) == -1) { close(sfd); } else { *port_free = true; close(sfd); } } return ecode; } void ProxySQL_Admin::load_or_update_global_settings(SQLite3DB *db) { char *error=NULL; int cols=0; int affected_rows=0; SQLite3_result *resultset=NULL; char *q=(char *)"SELECT variable_name, variable_value FROM global_settings ORDER BY variable_name"; db->execute_statement(q, &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", q, error); } else { // note: we don't lock, this is done only during bootstrap { char *uuid = NULL; bool write_uuid = true; // search for uuid for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; if (strcasecmp(r->fields[0],"uuid")==0) { uuid = strdup(r->fields[1]); uuid_t uu; if (uuid) { if (uuid_parse(uuid,uu)==0) { // we successful read an UUID } else { proxy_error("Ignoring invalid UUID format in global_settings: %s\n", uuid); free(uuid); uuid = NULL; } } } } if (uuid) { // we found an UUID in the DB if (GloVars.uuid) { // an UUID is already defined if (strcmp(uuid, GloVars.uuid)==0) { // the match proxy_info("Using UUID: %s\n", uuid); write_uuid = false; } else { // they do not match. The one on DB will be replaced proxy_info("Using UUID: %s . Replacing UUID from database: %s\n", GloVars.uuid, uuid); } } else { // the UUID already defined, so the one in the DB will be used proxy_info("Using UUID from database: %s\n", uuid); GloVars.uuid=strdup(uuid); } } else { if (GloVars.uuid) { // we will write the UUID in the DB proxy_info("Using UUID: %s . Writing it to database\n", GloVars.uuid); } else { // UUID not defined anywhere, we will create a new one uuid_t uu; uuid_generate(uu); char buf[40]; uuid_unparse(uu, buf); GloVars.uuid=strdup(buf); proxy_info("Using UUID: %s , randomly generated. Writing it to database\n", GloVars.uuid); } } if (write_uuid) { std::string s = "INSERT OR REPLACE INTO global_settings VALUES (\"uuid\", \""; s += GloVars.uuid; s += "\")"; db->execute(s.c_str()); } if (uuid) { free(uuid); uuid=NULL; } } if (resultset) { delete resultset; } } } void ProxySQL_Admin::load_restapi_server() { if (!all_modules_started) { return; } std::function(const httpserver::http_request&)> prometheus_callback { [this](const httpserver::http_request& request) { auto headers = request_headers(request); auto serial_response = this->serial_exposer(headers); auto http_response = make_response(serial_response); return http_response; } }; bool free_restapi_port = false; // Helper lambda taking a boolean reference as a parameter to check if 'restapi_port' is available. // In case of port not being free or error, logs an error 'ProxySQL_RestAPI_Server' isn't able to be started. const auto check_restapi_port = [&](bool& restapi_port_free) -> void { int e_port_check = check_port_availability(variables.restapi_port, &restapi_port_free); if (restapi_port_free == false) { if (e_port_check == -1) { proxy_error("Unable to start 'ProxySQL_RestAPI_Server', failed to set 'SO_REUSEADDR' to check port availability.\n"); } else { proxy_error( "Unable to start 'ProxySQL_RestAPI_Server', port '%d' already in use.\n", variables.restapi_port ); } } }; if (variables.restapi_enabled != variables.restapi_enabled_old) { if (variables.restapi_enabled) { check_restapi_port(free_restapi_port); } if (variables.restapi_enabled && free_restapi_port) { AdminRestApiServer = new ProxySQL_RESTAPI_Server( variables.restapi_port, {{"/metrics", prometheus_callback}} ); } else { delete AdminRestApiServer; AdminRestApiServer = NULL; } variables.restapi_enabled_old = variables.restapi_enabled; } else { if (variables.restapi_port != variables.restapi_port_old) { if (AdminRestApiServer) { delete AdminRestApiServer; AdminRestApiServer = NULL; } if (variables.restapi_enabled) { check_restapi_port(free_restapi_port); } if (variables.restapi_enabled && free_restapi_port) { AdminRestApiServer = new ProxySQL_RESTAPI_Server( variables.restapi_port, {{"/metrics", prometheus_callback}} ); } variables.restapi_port_old = variables.restapi_port; } } } void ProxySQL_Admin::load_http_server() { if (!all_modules_started) { return; } if (variables.web_enabled != variables.web_enabled_old) { if (variables.web_enabled) { if (GloVars.web_interface_plugin == NULL) { char *key_pem; char *cert_pem; GloVars.get_SSL_pem_mem(&key_pem, &cert_pem); Admin_HTTP_Server = MHD_start_daemon(MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_SSL, variables.web_port, NULL, NULL, http_handler, NULL, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120, MHD_OPTION_STRICT_FOR_CLIENT, (int) 1, MHD_OPTION_THREAD_POOL_SIZE, (unsigned int) 4, MHD_OPTION_NONCE_NC_SIZE, (unsigned int) 300, MHD_OPTION_HTTPS_MEM_KEY, key_pem, MHD_OPTION_HTTPS_MEM_CERT, cert_pem, MHD_OPTION_END); free(key_pem); free(cert_pem); } else { if (GloWebInterface) { int sfd = 0; int reuseaddr = 1; struct sockaddr_in tmp_addr; sfd = socket(AF_INET, SOCK_STREAM, 0); memset(&tmp_addr, 0, sizeof(tmp_addr)); tmp_addr.sin_family = AF_INET; tmp_addr.sin_port = htons(variables.web_port); tmp_addr.sin_addr.s_addr = INADDR_ANY; if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr, sizeof(reuseaddr)) == -1) { close(sfd); proxy_error( "Unable to start WebInterfacePlugin, failed to set 'SO_REUSEADDR' to check port '%d' availability.\n", variables.web_port ); } else { if (::bind(sfd, (struct sockaddr*)&tmp_addr, (socklen_t)sizeof(tmp_addr)) == -1) { close(sfd); proxy_error( "Unable to start WebInterfacePlugin, port '%d' already in use.\n", variables.web_port ); } else { close(sfd); GloWebInterface->start(variables.web_port); } } } } } else { if (GloVars.web_interface_plugin == NULL) { MHD_stop_daemon(Admin_HTTP_Server); Admin_HTTP_Server = NULL; } else { if (GloWebInterface) { GloWebInterface->stop(); } } } variables.web_enabled_old = variables.web_enabled; } else { if (variables.web_port != variables.web_port_old) { if (variables.web_enabled) { if (GloVars.web_interface_plugin == NULL) { MHD_stop_daemon(Admin_HTTP_Server); Admin_HTTP_Server = NULL; char *key_pem; char *cert_pem; GloVars.get_SSL_pem_mem(&key_pem, &cert_pem); Admin_HTTP_Server = MHD_start_daemon(MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_SSL, variables.web_port, NULL, NULL, http_handler, NULL, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120, MHD_OPTION_STRICT_FOR_CLIENT, (int) 1, MHD_OPTION_THREAD_POOL_SIZE, (unsigned int) 4, MHD_OPTION_NONCE_NC_SIZE, (unsigned int) 300, MHD_OPTION_HTTPS_MEM_KEY, key_pem, MHD_OPTION_HTTPS_MEM_CERT, cert_pem, MHD_OPTION_END); free(key_pem); free(cert_pem); } else { if (GloWebInterface) { GloWebInterface->start(variables.web_port); } } } variables.web_port_old = variables.web_port; } } } 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;i 0) { if ((ssl_keylog_file[0] != '/')) { // relative path char* tmp_ssl_keylog_file = (char*)malloc(strlen(GloVars.datadir) + strlen(ssl_keylog_file) + 2); sprintf(tmp_ssl_keylog_file, "%s/%s", GloVars.datadir, ssl_keylog_file); free(ssl_keylog_file); ssl_keylog_file = tmp_ssl_keylog_file; } } return ssl_keylog_file; } return NULL; } template #ifdef DEBUG void ProxySQL_Admin::add_credentials(char *type, char *credentials, int hostgroup_id) { #else void ProxySQL_Admin::add_credentials(char *credentials, int hostgroup_id) { #endif /* DEBUG */ proxy_debug(PROXY_DEBUG_ADMIN, 4, "Adding %s credentials: %s\n", type, credentials); tokenizer_t tok; tokenizer( &tok, 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, "Adding %s credential: \"%s\", user:%s, pass:%s\n", type, token, user, pass); if constexpr (pt == SERVER_TYPE_MYSQL) { if (GloMyAuth) { // this check if required if GloMyAuth doesn't exist yet GloMyAuth->add(user, pass, USERNAME_FRONTEND, 0, hostgroup_id, (char*)"main", 0, 0, 0, 1000, (char*)"", (char*)""); } } else if constexpr (pt == SERVER_TYPE_PGSQL) { if (GloPgAuth) { // this check if required if GloPgAuth doesn't exist yet GloPgAuth->add(user, pass, USERNAME_FRONTEND, 0, hostgroup_id, 0, 0, 1000, (char*)"", (char*)""); } } free(user); free(pass); } free_tokenizer( &tok ); } template #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( &tok, 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 constexpr (pt == SERVER_TYPE_MYSQL) { if (GloMyAuth) { // this check if required if GloMyAuth doesn't exist yet GloMyAuth->del(user, USERNAME_FRONTEND); } } else if constexpr (pt == SERVER_TYPE_PGSQL) { if (GloPgAuth) { // this check if required if GloPgAuth doesn't exist yet GloPgAuth->del(user, USERNAME_FRONTEND); } } free(user); free(pass); } free_tokenizer( &tok ); } bool ProxySQL_Admin::set_variable(char *name, char *value, bool lock) { // 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); delete_credentials((char *)"admin",variables.admin_credentials); #else delete_credentials(variables.admin_credentials); 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); add_credentials((char*)"admin", variables.admin_credentials, ADMIN_HOSTGROUP); #else add_credentials(variables.admin_credentials, ADMIN_HOSTGROUP); 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); delete_credentials((char*)"stats", variables.stats_credentials); #else delete_credentials(variables.stats_credentials); 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); add_credentials((char*)"admin", variables.stats_credentials, STATS_HOSTGROUP); #else add_credentials(variables.stats_credentials, STATS_HOSTGROUP); add_credentials(variables.stats_credentials, STATS_HOSTGROUP); #endif /* DEBUG */ } return true; } else { return false; } } if (!strncasecmp(name,"stats_",strlen("stats_"))) { if (!strcasecmp(name,"stats_mysql_connection_pool")) { int intv=atoi(value); if (intv >= 0 && intv <= 300) { intv = round_intv_to_time_interval(name, intv); variables.stats_mysql_connection_pool=intv; GloProxyStats->variables.stats_mysql_connection_pool=intv; return true; } else { return false; } } if (!strcasecmp(name,"stats_mysql_connections")) { int intv=atoi(value); if (intv >= 0 && intv <= 300) { intv = round_intv_to_time_interval(name, intv); variables.stats_mysql_connections=intv; GloProxyStats->variables.stats_mysql_connections=intv; return true; } else { return false; } } if (!strcasecmp(name,"stats_mysql_query_cache")) { int intv=atoi(value); if (intv >= 0 && intv <= 300) { intv = round_intv_to_time_interval(name, intv); variables.stats_mysql_query_cache=intv; GloProxyStats->variables.stats_mysql_query_cache=intv; return true; } else { return false; } } if (!strcasecmp(name,"stats_mysql_query_digest_to_disk")) { int intv=atoi(value); if (intv >= 0 && intv <= 24*3600) { variables.stats_mysql_query_digest_to_disk=intv; GloProxyStats->variables.stats_mysql_query_digest_to_disk=intv; return true; } else { return false; } } if (!strcasecmp(name,"stats_mysql_eventslog_sync_buffer_to_disk")) { int intv=atoi(value); if (intv >= 0 && intv <= 24*3600) { variables.stats_mysql_eventslog_sync_buffer_to_disk=intv; GloProxyStats->variables.stats_mysql_eventslog_sync_buffer_to_disk=intv; return true; } else { return false; } } if (!strcasecmp(name,"stats_system_cpu")) { int intv=atoi(value); if (intv >= 0 && intv <= 600) { intv = round_intv_to_time_interval(name, intv); variables.stats_system_cpu=intv; GloProxyStats->variables.stats_system_cpu=intv; return true; } else { return false; } } #ifndef NOJEM if (!strcasecmp(name,"stats_system_memory")) { int intv=atoi(value); if (intv >= 0 && intv <= 600) { intv = round_intv_to_time_interval(name, intv); variables.stats_system_memory=intv; GloProxyStats->variables.stats_system_memory=intv; return true; } else { return false; } } #endif } 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); } GloProxyCluster->set_admin_mysql_ifaces(value); return true; } else { return false; } } if (!strcasecmp(name, "pgsql_ifaces")) { if (vallen) { bool update_creds = false; if ((variables.pgsql_ifaces == NULL) || strcasecmp(variables.pgsql_ifaces, value)) update_creds = true; if (variables.pgsql_ifaces) free(variables.pgsql_ifaces); variables.pgsql_ifaces = strdup(value); if (update_creds && variables.pgsql_ifaces) { S_amll.update_ifaces(variables.pgsql_ifaces, &S_amll.ifaces_pgsql); } //GloProxyCluster->set_admin_pgsql_ifaces(value); return true; } else { return false; } } if (!strcasecmp(name,"cluster_username")) { if (vallen) { free(variables.cluster_username); variables.cluster_username=strdup(value); GloProxyCluster->set_username(variables.cluster_username); return true; } else { return true; } } if (!strcasecmp(name,"cluster_password")) { if (vallen) { free(variables.cluster_password); variables.cluster_password=strdup(value); GloProxyCluster->set_password(variables.cluster_password); return true; } else { return true; } } 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,"cluster_check_interval_ms")) { int intv=atoi(value); if (intv >= 10 && intv <= 300000) { variables.cluster_check_interval_ms=intv; __sync_lock_test_and_set(&GloProxyCluster->cluster_check_interval_ms, intv); return true; } else { return false; } } if (!strcasecmp(name,"cluster_check_status_frequency")) { int intv=atoi(value); if (intv >= 0 && intv <= 10000) { variables.cluster_check_status_frequency=intv; __sync_lock_test_and_set(&GloProxyCluster->cluster_check_status_frequency, intv); return true; } else { return false; } } if (!strcasecmp(name,"cluster_mysql_query_rules_diffs_before_sync")) { int intv=atoi(value); if (intv >= 0 && intv <= 1000) { intv = checksum_variables.checksum_mysql_query_rules ? intv : 0; if (variables.cluster_mysql_query_rules_diffs_before_sync == 0 && intv != 0) { proxy_info("Re-enabled previously disabled 'admin-cluster_admin_variables_diffs_before_sync'. Resetting global checksums to force Cluster re-sync.\n"); GloProxyCluster->Reset_Global_Checksums(lock); } variables.cluster_mysql_query_rules_diffs_before_sync=intv; __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_query_rules_diffs_before_sync, intv); return true; } else { return false; } } if (!strcasecmp(name,"cluster_mysql_servers_diffs_before_sync")) { int intv=atoi(value); if (intv >= 0 && intv <= 1000) { intv = checksum_variables.checksum_mysql_servers ? intv : 0; if (variables.cluster_mysql_servers_diffs_before_sync == 0 && intv != 0) { proxy_info("Re-enabled previously disabled 'admin-cluster_mysql_servers_diffs_before_sync'. Resetting global checksums to force Cluster re-sync.\n"); GloProxyCluster->Reset_Global_Checksums(lock); } variables.cluster_mysql_servers_diffs_before_sync=intv; __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_servers_diffs_before_sync, intv); return true; } else { return false; } } if (!strcasecmp(name,"cluster_mysql_users_diffs_before_sync")) { int intv=atoi(value); if (intv >= 0 && intv <= 1000) { intv = checksum_variables.checksum_mysql_users ? intv : 0; if (variables.cluster_mysql_users_diffs_before_sync == 0 && intv != 0) { proxy_info("Re-enabled previously disabled 'admin-cluster_mysql_users_diffs_before_sync'. Resetting global checksums to force Cluster re-sync.\n"); GloProxyCluster->Reset_Global_Checksums(lock); } variables.cluster_mysql_users_diffs_before_sync=intv; __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_users_diffs_before_sync, intv); return true; } else { return false; } } if (!strcasecmp(name,"cluster_proxysql_servers_diffs_before_sync")) { int intv=atoi(value); if (intv >= 0 && intv <= 1000) { if (variables.cluster_proxysql_servers_diffs_before_sync == 0 && intv != 0) { proxy_info("Re-enabled previously disabled 'admin-cluster_proxysql_servers_diffs_before_sync'. Resetting global checksums to force Cluster re-sync.\n"); GloProxyCluster->Reset_Global_Checksums(lock); } variables.cluster_proxysql_servers_diffs_before_sync=intv; __sync_lock_test_and_set(&GloProxyCluster->cluster_proxysql_servers_diffs_before_sync, intv); return true; } else { return false; } } if (!strcasecmp(name,"cluster_mysql_variables_diffs_before_sync")) { int intv=atoi(value); if (intv >= 0 && intv <= 1000) { intv = checksum_variables.checksum_mysql_variables ? intv : 0; if (variables.cluster_mysql_variables_diffs_before_sync == 0 && intv != 0) { proxy_info("Re-enabled previously disabled 'admin-cluster_mysql_variables_diffs_before_sync'. Resetting global checksums to force Cluster re-sync.\n"); GloProxyCluster->Reset_Global_Checksums(lock); } variables.cluster_mysql_variables_diffs_before_sync=intv; __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_variables_diffs_before_sync, intv); return true; } else { return false; } } if (!strcasecmp(name,"cluster_admin_variables_diffs_before_sync")) { int intv=atoi(value); if (intv >= 0 && intv <= 1000) { intv = checksum_variables.checksum_admin_variables ? intv : 0; if (variables.cluster_admin_variables_diffs_before_sync == 0 && intv != 0) { proxy_info("Re-enabled previously disabled 'admin-cluster_admin_variables_diffs_before_sync'. Resetting global checksums to force Cluster re-sync.\n"); GloProxyCluster->Reset_Global_Checksums(lock); } variables.cluster_admin_variables_diffs_before_sync=intv; __sync_lock_test_and_set(&GloProxyCluster->cluster_admin_variables_diffs_before_sync, intv); return true; } else { return false; } } if (!strcasecmp(name,"cluster_ldap_variables_diffs_before_sync")) { int intv=atoi(value); if (intv >= 0 && intv <= 1000) { intv = checksum_variables.checksum_ldap_variables ? intv : 0; if (variables.cluster_ldap_variables_diffs_before_sync == 0 && intv != 0) { proxy_info("Re-enabled previously disabled 'admin-cluster_ldap_variables_diffs_before_sync'. Resetting global checksums to force Cluster re-sync.\n"); GloProxyCluster->Reset_Global_Checksums(lock); } variables.cluster_ldap_variables_diffs_before_sync=intv; __sync_lock_test_and_set(&GloProxyCluster->cluster_ldap_variables_diffs_before_sync, intv); return true; } else { return false; } } if (!strcasecmp(name,"cluster_mysql_servers_sync_algorithm")) { int intv=atoi(value); if (intv >= 1 && intv <= 3) { if (variables.cluster_mysql_servers_sync_algorithm != intv) { proxy_info("'cluster_mysql_servers_sync_algorithm' updated. Resetting global checksums to force Cluster re-sync.\n"); GloProxyCluster->Reset_Global_Checksums(lock); } variables.cluster_mysql_servers_sync_algorithm=intv; __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_servers_sync_algorithm, 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")) { proxy_warning("Variable admin-hash_passwords is now deprecated and removed. See github issue #4218\n"); /* if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.hash_passwords=true; if (GloMyLdapAuth) { proxy_info("Impossible to set admin-hash_passwords=true when LDAP is enabled. Reverting to false\n"); variables.hash_passwords=false; } return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { variables.hash_passwords=false; return true; } return false; */ } if (!strcasecmp(name,"vacuum_stats")) { if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.vacuum_stats=true; return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { variables.vacuum_stats=false; return true; } return false; } if (!strcasecmp(name,"restapi_enabled")) { if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.restapi_enabled=true; return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { variables.restapi_enabled=false; return true; } return false; } if (!strcasecmp(name,"restapi_port")) { int intv=atoi(value); if (intv > 0 && intv < 65535) { variables.restapi_port=intv; return true; } else { return false; } } if (!strcasecmp(name,"web_enabled")) { if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.web_enabled=true; return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { variables.web_enabled=false; return true; } return false; } if (!strcasecmp(name,"web_port")) { int intv=atoi(value); if (intv > 0 && intv < 65535) { variables.web_port=intv; return true; } else { return false; } } if (!strcasecmp(name,"web_verbosity")) { int intv=atoi(value); if (intv >= 0 && intv <= 10) { variables.web_verbosity=intv; return true; } else { return false; } } if (!strcasecmp(name,"cluster_mysql_query_rules_save_to_disk")) { bool rt = false; if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.cluster_mysql_query_rules_save_to_disk=true; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_query_rules_save_to_disk, true); return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { variables.cluster_mysql_query_rules_save_to_disk=false; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_query_rules_save_to_disk, false); return true; } return rt; } if (!strcasecmp(name,"cluster_mysql_servers_save_to_disk")) { bool rt = false; if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.cluster_mysql_servers_save_to_disk=true; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_servers_save_to_disk, true); return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { variables.cluster_mysql_servers_save_to_disk=false; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_servers_save_to_disk, false); return true; } return rt; } if (!strcasecmp(name,"cluster_mysql_users_save_to_disk")) { bool rt = false; if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.cluster_mysql_users_save_to_disk=true; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_users_save_to_disk, true); return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { variables.cluster_mysql_users_save_to_disk=false; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_users_save_to_disk, false); return true; } return rt; } if (!strcasecmp(name,"cluster_proxysql_servers_save_to_disk")) { bool rt = false; if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.cluster_proxysql_servers_save_to_disk=true; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_proxysql_servers_save_to_disk, true); return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { variables.cluster_proxysql_servers_save_to_disk=false; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_proxysql_servers_save_to_disk, false); return true; } return rt; } if (!strcasecmp(name,"cluster_mysql_variables_save_to_disk")) { bool rt = false; if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.cluster_mysql_variables_save_to_disk=true; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_variables_save_to_disk, true); return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { variables.cluster_mysql_variables_save_to_disk=false; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_variables_save_to_disk, false); return true; } return rt; } if (!strcasecmp(name,"cluster_admin_variables_save_to_disk")) { bool rt = false; if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.cluster_admin_variables_save_to_disk=true; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_admin_variables_save_to_disk, true); return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { variables.cluster_admin_variables_save_to_disk=false; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_admin_variables_save_to_disk, false); return true; } return rt; } if (!strcasecmp(name,"cluster_ldap_variables_save_to_disk")) { bool rt = false; if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { variables.cluster_ldap_variables_save_to_disk=true; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_ldap_variables_save_to_disk, true); return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { variables.cluster_ldap_variables_save_to_disk=false; rt = __sync_lock_test_and_set(&GloProxyCluster->cluster_ldap_variables_save_to_disk, false); return true; } return rt; } if (!strcasecmp(name,"checksum_mysql_query_rules")) { if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { checksum_variables.checksum_mysql_query_rules=true; return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { checksum_variables.checksum_mysql_query_rules=false; variables.cluster_mysql_query_rules_diffs_before_sync = 0; __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_query_rules_diffs_before_sync, 0); proxy_warning("Disabling deprecated 'admin-checksum_mysql_query_rules', setting 'admin-cluster_mysql_query_rules_diffs_before_sync=0'\n"); return true; } return false; } if (!strcasecmp(name,"checksum_mysql_servers")) { if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { checksum_variables.checksum_mysql_servers=true; return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { checksum_variables.checksum_mysql_servers=false; variables.cluster_mysql_servers_diffs_before_sync = 0; __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_servers_diffs_before_sync, 0); proxy_warning("Disabling deprecated 'admin-checksum_mysql_servers', setting 'admin-cluster_mysql_servers_diffs_before_sync=0'\n"); return true; } return false; } if (!strcasecmp(name,"checksum_mysql_users")) { if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { checksum_variables.checksum_mysql_users=true; return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { checksum_variables.checksum_mysql_users=false; variables.cluster_mysql_users_diffs_before_sync = 0; __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_users_diffs_before_sync, 0); proxy_warning("Disabling deprecated 'admin-checksum_mysql_users', setting 'admin-cluster_mysql_users_diffs_before_sync=0'\n"); return true; } return false; } if (!strcasecmp(name,"checksum_mysql_variables")) { if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { checksum_variables.checksum_mysql_variables=true; return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { checksum_variables.checksum_mysql_variables=false; variables.cluster_mysql_variables_diffs_before_sync = 0; __sync_lock_test_and_set(&GloProxyCluster->cluster_mysql_variables_diffs_before_sync, 0); proxy_warning("Disabling deprecated 'admin-checksum_mysql_variables', setting 'admin-cluster_mysql_variables_diffs_before_sync=0'\n"); return true; } return false; } if (!strcasecmp(name,"checksum_admin_variables")) { if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { checksum_variables.checksum_admin_variables=true; return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { checksum_variables.checksum_admin_variables=false; variables.cluster_admin_variables_diffs_before_sync = 0; __sync_lock_test_and_set(&GloProxyCluster->cluster_admin_variables_diffs_before_sync, 0); proxy_warning("Disabling deprecated 'admin-checksum_admin_variables', setting 'admin-cluster_admin_variables_diffs_before_sync=0'\n"); return true; } return false; } if (!strcasecmp(name,"checksum_ldap_variables")) { if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { checksum_variables.checksum_ldap_variables=true; return true; } if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { checksum_variables.checksum_ldap_variables=false; variables.cluster_ldap_variables_diffs_before_sync = 0; __sync_lock_test_and_set(&GloProxyCluster->cluster_ldap_variables_diffs_before_sync, 0); proxy_warning("Disabling deprecated 'admin-checksum_ldap_variables', setting 'admin-cluster_ldap_variables_diffs_before_sync=0'\n"); 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; } if (!strcasecmp(name,"prometheus_memory_metrics_interval")) { const auto fval = atoi(value); if (fval > 0 && fval < 7*24*3600) { variables.p_memory_metrics_interval = fval; return true; } else { 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; } if (!strcasecmp(name,"debug_output")) { const auto fval = atoi(value); if (fval > 0 && fval <= 3) { debug_output = fval; proxysql_set_admin_debug_output(debug_output); return true; } else { return false; } return false; } #endif /* DEBUG */ if (!strcasecmp(name,"coredump_generation_interval_ms")) { int intv=atoi(value); if (intv >= 0 && intv < INT_MAX) { variables.coredump_generation_interval_ms=intv; coredump_generation_interval_ms=intv; return true; } else { return false; } } if (!strcasecmp(name,"coredump_generation_threshold")) { int intv=atoi(value); if (intv > 0 && intv <= 500) { variables.coredump_generation_threshold=intv; coredump_generation_threshold=intv; return true; } else { return false; } } if (!strcasecmp(name, "ssl_keylog_file")) { if (strcmp(variables.ssl_keylog_file, value)) { if (vallen == 0 || strcmp(value, "(null)") == 0) { proxysql_keylog_close(); free(variables.ssl_keylog_file); variables.ssl_keylog_file = strdup(""); GloVars.global.ssl_keylog_enabled = false; } else { char* sslkeylogfile = NULL; const bool is_absolute_path = (value[0] == '/'); if (is_absolute_path) { // absolute path sslkeylogfile = strdup(value); } else { // relative path sslkeylogfile = (char*)malloc(strlen(GloVars.datadir) + strlen(value) + 2); sprintf(sslkeylogfile, "%s/%s", GloVars.datadir, value); } if (proxysql_keylog_open(sslkeylogfile) == false) { free(sslkeylogfile); proxy_warning("Cannot open SSLKEYLOGFILE '%s' for writing.\n", value); return false; } free(variables.ssl_keylog_file); if (is_absolute_path) { variables.ssl_keylog_file = sslkeylogfile; sslkeylogfile = NULL; } else { variables.ssl_keylog_file = strdup(value); } if (sslkeylogfile) free(sslkeylogfile); GloVars.global.ssl_keylog_enabled = true; } } return true; } return false; } void ProxySQL_Admin::save_mysql_query_rules_fast_routing_from_runtime(bool _runtime) { if (_runtime) { admindb->execute("DELETE FROM runtime_mysql_query_rules_fast_routing"); } else { admindb->execute("DELETE FROM mysql_query_rules_fast_routing"); } SQLite3_result * resultset=GloMyQPro->get_current_query_rules_fast_routing(); if (resultset) { int rc; sqlite3_stmt *statement1=NULL; sqlite3_stmt *statement32=NULL; char *query1=NULL; char *query32=NULL; std::string query32s = ""; if (_runtime) { query1=(char *)"INSERT INTO runtime_mysql_query_rules_fast_routing VALUES (?1, ?2, ?3, ?4, ?5)"; query32s = "INSERT INTO runtime_mysql_query_rules_fast_routing VALUES " + generate_multi_rows_query(32,5); query32 = (char *)query32s.c_str(); } else { query1=(char *)"INSERT INTO mysql_query_rules_fast_routing VALUES (?1, ?2, ?3, ?4, ?5)"; query32s = "INSERT INTO mysql_query_rules_fast_routing VALUES " + generate_multi_rows_query(32,5); query32 = (char *)query32s.c_str(); } rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, admindb); int row_idx=0; int max_bulk_row_idx=resultset->rows_count/32; max_bulk_row_idx=max_bulk_row_idx*32; for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r1=*it; int idx=row_idx%32; if (row_idxfields[0], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*5)+2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*5)+3, atoi(r1->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*5)+4, atoi(r1->fields[3])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*5)+5, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx==31) { SAFE_SQLITE3_STEP2(statement32); rc=(*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc=(*proxy_sqlite3_bind_text)(statement1, 1, r1->fields[0], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, atoi(r1->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 4, atoi(r1->fields[3])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 5, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); } if(resultset) delete resultset; resultset = NULL; } void ProxySQL_Admin::save_pgsql_query_rules_fast_routing_from_runtime(bool _runtime) { if (_runtime) { admindb->execute("DELETE FROM runtime_pgsql_query_rules_fast_routing"); } else { admindb->execute("DELETE FROM pgsql_query_rules_fast_routing"); } SQLite3_result* resultset = GloPgQPro->get_current_query_rules_fast_routing(); if (resultset) { int rc; sqlite3_stmt* statement1 = NULL; sqlite3_stmt* statement32 = NULL; //sqlite3 *mydb3=admindb->get_db(); char* query1 = NULL; char* query32 = NULL; std::string query32s = ""; if (_runtime) { query1 = (char*)"INSERT INTO runtime_pgsql_query_rules_fast_routing VALUES (?1, ?2, ?3, ?4, ?5)"; query32s = "INSERT INTO runtime_pgsql_query_rules_fast_routing VALUES " + generate_multi_rows_query(32, 5); query32 = (char*)query32s.c_str(); } else { query1 = (char*)"INSERT INTO pgsql_query_rules_fast_routing VALUES (?1, ?2, ?3, ?4, ?5)"; query32s = "INSERT INTO pgsql_query_rules_fast_routing VALUES " + generate_multi_rows_query(32, 5); query32 = (char*)query32s.c_str(); } //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query1, -1, &statement1, 0); rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query32, -1, &statement32, 0); rc = admindb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, admindb); int row_idx = 0; int max_bulk_row_idx = resultset->rows_count / 32; max_bulk_row_idx = max_bulk_row_idx * 32; for (std::vector::iterator it = resultset->rows.begin(); it != resultset->rows.end(); ++it) { SQLite3_row* r1 = *it; int idx = row_idx % 32; if (row_idx < max_bulk_row_idx) { // bulk rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 5) + 1, r1->fields[0], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 5) + 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 5) + 3, atoi(r1->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 5) + 4, atoi(r1->fields[3])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 5) + 5, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx == 31) { SAFE_SQLITE3_STEP2(statement32); rc = (*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc = (*proxy_sqlite3_bind_text)(statement1, 1, r1->fields[0], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 3, atoi(r1->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 4, atoi(r1->fields[3])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 5, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); } if (resultset) delete resultset; resultset = NULL; } void ProxySQL_Admin::save_mysql_query_rules_from_runtime(bool _runtime) { if (_runtime) { admindb->execute("DELETE FROM runtime_mysql_query_rules"); } else { admindb->execute("DELETE FROM mysql_query_rules"); } SQLite3_result * resultset=GloMyQPro->get_current_query_rules(); if (resultset==NULL) return; //char *a=(char *)"INSERT INTO mysql_query_rules VALUES (\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")"; char *a=NULL; if (_runtime) { a=(char *)"INSERT INTO runtime_mysql_query_rules (rule_id, active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, OK_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, attributes, comment) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"; } else { a=(char *)"INSERT INTO mysql_query_rules (rule_id, active, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, OK_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, attributes, comment) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"; } for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; int arg_len=0; char *buffs[35]; // number of fields for (int i=0; i<35; i++) { if (r->fields[i]) { char *o=escape_string_single_quotes(r->fields[i],false); int l=strlen(o)+4; arg_len+=l; buffs[i]=(char *)malloc(l); sprintf(buffs[i],"'%s'",o); if (o!=r->fields[i]) { // there was a copy free(o); } } else { int l=9; arg_len+=l; buffs[i]=(char *)malloc(l); sprintf(buffs[i],"NULL"); } } char *query=(char *)malloc(strlen(a)+arg_len+32); sprintf(query,a, buffs[0], buffs[1], buffs[2], buffs[3], ( strcmp(r->fields[4],"-1")==0 ? "NULL" : r->fields[4] ), // flagIN buffs[5], // client_addr buffs[6], // proxy_addr ( strcmp(r->fields[7],"-1")==0 ? "NULL" : r->fields[7] ), // proxy_port buffs[8], // digest buffs[9], // match_digest buffs[10], // match_pattern r->fields[11], // negate buffs[12], // re_modifiers ( strcmp(r->fields[13],"-1")==0 ? "NULL" : r->fields[13] ), // flagOUT buffs[14], // replace_pattern ( strcmp(r->fields[15],"-1")==0 ? "NULL" : r->fields[15] ), // destination_hostgroup ( strcmp(r->fields[16],"-1")==0 ? "NULL" : r->fields[16] ), // cache_ttl ( strcmp(r->fields[17],"-1")==0 ? "NULL" : r->fields[17] ), // cache_empty_result ( strcmp(r->fields[18],"-1")==0 ? "NULL" : r->fields[18] ), // cache_timeout ( strcmp(r->fields[19],"-1")==0 ? "NULL" : r->fields[19] ), // reconnect ( strcmp(r->fields[20],"-1")==0 ? "NULL" : r->fields[20] ), // timeout ( strcmp(r->fields[21],"-1")==0 ? "NULL" : r->fields[21] ), // retries ( strcmp(r->fields[22],"-1")==0 ? "NULL" : r->fields[22] ), // delay ( strcmp(r->fields[23],"-1")==0 ? "NULL" : r->fields[23] ), // next_query_flagIN ( strcmp(r->fields[24],"-1")==0 ? "NULL" : r->fields[24] ), // mirror_flagOUT ( strcmp(r->fields[25],"-1")==0 ? "NULL" : r->fields[25] ), // mirror_hostgroup buffs[26], // error_msg buffs[27], // OK_msg ( strcmp(r->fields[28],"-1")==0 ? "NULL" : r->fields[28] ), // sticky_conn ( strcmp(r->fields[29],"-1")==0 ? "NULL" : r->fields[29] ), // multiplex ( strcmp(r->fields[30],"-1")==0 ? "NULL" : r->fields[30] ), // gtid_from_hostgroup ( strcmp(r->fields[31],"-1")==0 ? "NULL" : r->fields[31] ), // log ( strcmp(r->fields[32],"-1")==0 ? "NULL" : r->fields[32] ), // apply buffs[33], // attributes buffs[34] // comment ); //fprintf(stderr,"%s\n",query); admindb->execute(query); for (int i=0; i<35; i++) { free(buffs[i]); } free(query); } delete resultset; } void ProxySQL_Admin::save_pgsql_query_rules_from_runtime(bool _runtime) { if (_runtime) { admindb->execute("DELETE FROM runtime_pgsql_query_rules"); } else { admindb->execute("DELETE FROM pgsql_query_rules"); } SQLite3_result* resultset = GloPgQPro->get_current_query_rules(); if (resultset == NULL) return; //char *a=(char *)"INSERT INTO pgsql_query_rules VALUES (\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")"; char* a = NULL; if (_runtime) { a = (char*)"INSERT INTO runtime_pgsql_query_rules (rule_id, active, username, database, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, OK_msg, sticky_conn, multiplex, log, apply, attributes, comment) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"; } else { a = (char*)"INSERT INTO pgsql_query_rules (rule_id, active, username, database, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, OK_msg, sticky_conn, multiplex, log, apply, attributes, comment) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"; } for (std::vector::iterator it = resultset->rows.begin(); it != resultset->rows.end(); ++it) { SQLite3_row* r = *it; int arg_len = 0; char* buffs[34]; // number of fields for (int i = 0; i < 34; i++) { if (r->fields[i]) { char* o = escape_string_single_quotes(r->fields[i], false); int l = strlen(o) + 4; arg_len += l; buffs[i] = (char*)malloc(l); sprintf(buffs[i], "'%s'", o); if (o != r->fields[i]) { // there was a copy free(o); } } else { int l = 9; arg_len += l; buffs[i] = (char*)malloc(l); sprintf(buffs[i], "NULL"); } } char* query = (char*)malloc(strlen(a) + arg_len + 32); sprintf(query, a, buffs[0], buffs[1], buffs[2], buffs[3], (strcmp(r->fields[4], "-1") == 0 ? "NULL" : r->fields[4]), // flagIN buffs[5], // client_addr buffs[6], // proxy_addr (strcmp(r->fields[7], "-1") == 0 ? "NULL" : r->fields[7]), // proxy_port buffs[8], // digest buffs[9], // match_digest buffs[10], // match_pattern r->fields[11], // negate buffs[12], // re_modifiers (strcmp(r->fields[13], "-1") == 0 ? "NULL" : r->fields[13]), // flagOUT buffs[14], // replace_pattern (strcmp(r->fields[15], "-1") == 0 ? "NULL" : r->fields[15]), // destination_hostgroup (strcmp(r->fields[16], "-1") == 0 ? "NULL" : r->fields[16]), // cache_ttl (strcmp(r->fields[17], "-1") == 0 ? "NULL" : r->fields[17]), // cache_empty_result (strcmp(r->fields[18], "-1") == 0 ? "NULL" : r->fields[18]), // cache_timeout (strcmp(r->fields[19], "-1") == 0 ? "NULL" : r->fields[19]), // reconnect (strcmp(r->fields[20], "-1") == 0 ? "NULL" : r->fields[20]), // timeout (strcmp(r->fields[21], "-1") == 0 ? "NULL" : r->fields[21]), // retries (strcmp(r->fields[22], "-1") == 0 ? "NULL" : r->fields[22]), // delay (strcmp(r->fields[23], "-1") == 0 ? "NULL" : r->fields[23]), // next_query_flagIN (strcmp(r->fields[24], "-1") == 0 ? "NULL" : r->fields[24]), // mirror_flagOUT (strcmp(r->fields[25], "-1") == 0 ? "NULL" : r->fields[25]), // mirror_hostgroup buffs[26], // error_msg buffs[27], // OK_msg (strcmp(r->fields[28], "-1") == 0 ? "NULL" : r->fields[28]), // sticky_conn (strcmp(r->fields[29], "-1") == 0 ? "NULL" : r->fields[29]), // multiplex (strcmp(r->fields[30], "-1") == 0 ? "NULL" : r->fields[30]), // log (strcmp(r->fields[31], "-1") == 0 ? "NULL" : r->fields[31]), // apply buffs[32], // attributes buffs[33] // comment ); //fprintf(stderr,"%s\n",query); admindb->execute(query); for (int i = 0; i < 34; i++) { free(buffs[i]); } free(query); } delete resultset; } void ProxySQL_Admin::save_mysql_firewall_whitelist_sqli_fingerprints_from_runtime(bool _runtime, SQLite3_result *resultset) { // NOTE: this function doesn't delete resultset. The caller must do it if (resultset) { int rc; sqlite3_stmt *statement1=NULL; sqlite3_stmt *statement32=NULL; char *query1=NULL; char *query32=NULL; std::string query32s = ""; if (_runtime) { query1=(char *)"INSERT INTO runtime_mysql_firewall_whitelist_sqli_fingerprints VALUES (?1, ?2)"; query32s = "INSERT INTO runtime_mysql_firewall_whitelist_sqli_fingerprints VALUES " + generate_multi_rows_query(32,2); query32 = (char *)query32s.c_str(); } else { query1=(char *)"INSERT INTO mysql_firewall_whitelist_sqli_fingerprints VALUES (?1, ?2)"; query32s = "INSERT INTO mysql_firewall_whitelist_sqli_fingerprints VALUES " + generate_multi_rows_query(32,2); query32 = (char *)query32s.c_str(); } rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, admindb); int row_idx=0; int max_bulk_row_idx=resultset->rows_count/32; max_bulk_row_idx=max_bulk_row_idx*32; for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r1=*it; int idx=row_idx%32; if (row_idxfields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*2)+2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx==31) { SAFE_SQLITE3_STEP2(statement32); rc=(*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc=(*proxy_sqlite3_bind_int64)(statement1, 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); } } void ProxySQL_Admin::save_pgsql_firewall_whitelist_sqli_fingerprints_from_runtime(bool _runtime, SQLite3_result* resultset) { // NOTE: this function doesn't delete resultset. The caller must do it if (resultset) { int rc; sqlite3_stmt* statement1 = NULL; sqlite3_stmt* statement32 = NULL; char* query1 = NULL; char* query32 = NULL; std::string query32s = ""; if (_runtime) { query1 = (char*)"INSERT INTO runtime_pgsql_firewall_whitelist_sqli_fingerprints VALUES (?1, ?2)"; query32s = "INSERT INTO runtime_pgsql_firewall_whitelist_sqli_fingerprints VALUES " + generate_multi_rows_query(32, 2); query32 = (char*)query32s.c_str(); } else { query1 = (char*)"INSERT INTO pgsql_firewall_whitelist_sqli_fingerprints VALUES (?1, ?2)"; query32s = "INSERT INTO pgsql_firewall_whitelist_sqli_fingerprints VALUES " + generate_multi_rows_query(32, 2); query32 = (char*)query32s.c_str(); } rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, admindb); int row_idx = 0; int max_bulk_row_idx = resultset->rows_count / 32; max_bulk_row_idx = max_bulk_row_idx * 32; for (std::vector::iterator it = resultset->rows.begin(); it != resultset->rows.end(); ++it) { SQLite3_row* r1 = *it; int idx = row_idx % 32; if (row_idx < max_bulk_row_idx) { // bulk rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 2) + 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 2) + 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx == 31) { SAFE_SQLITE3_STEP2(statement32); rc = (*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc = (*proxy_sqlite3_bind_int64)(statement1, 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); } } void ProxySQL_Admin::save_mysql_firewall_whitelist_users_from_runtime(bool _runtime, SQLite3_result *resultset) { // NOTE: this function doesn't delete resultset. The caller must do it if (resultset) { int rc; sqlite3_stmt *statement1=NULL; sqlite3_stmt *statement32=NULL; char *query1=NULL; char *query32=NULL; std::string query32s = ""; if (_runtime) { query1=(char *)"INSERT INTO runtime_mysql_firewall_whitelist_users VALUES (?1, ?2, ?3, ?4, ?5)"; query32s = "INSERT INTO runtime_mysql_firewall_whitelist_users VALUES " + generate_multi_rows_query(32,5); query32 = (char *)query32s.c_str(); } else { query1=(char *)"INSERT INTO mysql_firewall_whitelist_users VALUES (?1, ?2, ?3, ?4, ?5)"; query32s = "INSERT INTO mysql_firewall_whitelist_users VALUES " + generate_multi_rows_query(32,5); query32 = (char *)query32s.c_str(); } rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, admindb); int row_idx=0; int max_bulk_row_idx=resultset->rows_count/32; max_bulk_row_idx=max_bulk_row_idx*32; for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r1=*it; int idx=row_idx%32; if (row_idxfields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*5)+2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*5)+3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*5)+4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*5)+5, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx==31) { SAFE_SQLITE3_STEP2(statement32); rc=(*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc=(*proxy_sqlite3_bind_int64)(statement1, 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 5, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); } } void ProxySQL_Admin::save_pgsql_firewall_whitelist_users_from_runtime(bool _runtime, SQLite3_result* resultset) { // NOTE: this function doesn't delete resultset. The caller must do it if (resultset) { int rc; sqlite3_stmt* statement1 = NULL; sqlite3_stmt* statement32 = NULL; char* query1 = NULL; char* query32 = NULL; std::string query32s = ""; if (_runtime) { query1 = (char*)"INSERT INTO runtime_pgsql_firewall_whitelist_users VALUES (?1, ?2, ?3, ?4, ?5)"; query32s = "INSERT INTO runtime_pgsql_firewall_whitelist_users VALUES " + generate_multi_rows_query(32, 5); query32 = (char*)query32s.c_str(); } else { query1 = (char*)"INSERT INTO pgsql_firewall_whitelist_users VALUES (?1, ?2, ?3, ?4, ?5)"; query32s = "INSERT INTO pgsql_firewall_whitelist_users VALUES " + generate_multi_rows_query(32, 5); query32 = (char*)query32s.c_str(); } rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, admindb); int row_idx = 0; int max_bulk_row_idx = resultset->rows_count / 32; max_bulk_row_idx = max_bulk_row_idx * 32; for (std::vector::iterator it = resultset->rows.begin(); it != resultset->rows.end(); ++it) { SQLite3_row* r1 = *it; int idx = row_idx % 32; if (row_idx < max_bulk_row_idx) { // bulk rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 5) + 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 5) + 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 5) + 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 5) + 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 5) + 5, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx == 31) { SAFE_SQLITE3_STEP2(statement32); rc = (*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc = (*proxy_sqlite3_bind_int64)(statement1, 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 5, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); } } void ProxySQL_Admin::save_mysql_firewall_whitelist_rules_from_runtime(bool _runtime, SQLite3_result *resultset) { // NOTE: this function doesn't delete resultset. The caller must do it if (resultset) { int rc; sqlite3_stmt *statement1=NULL; sqlite3_stmt *statement32=NULL; char *query1=NULL; char *query32=NULL; std::string query32s = ""; if (_runtime) { query1=(char *)"INSERT INTO runtime_mysql_firewall_whitelist_rules VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"; query32s = "INSERT INTO runtime_mysql_firewall_whitelist_rules VALUES " + generate_multi_rows_query(32,7); query32 = (char *)query32s.c_str(); } else { query1=(char *)"INSERT INTO mysql_firewall_whitelist_rules VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"; query32s = "INSERT INTO mysql_firewall_whitelist_rules VALUES " + generate_multi_rows_query(32,7); query32 = (char *)query32s.c_str(); } rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, admindb); int row_idx=0; int max_bulk_row_idx=resultset->rows_count/32; max_bulk_row_idx=max_bulk_row_idx*32; for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r1=*it; int idx=row_idx%32; if (row_idxfields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*7)+2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*7)+3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*7)+4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*7)+5, atoi(r1->fields[4])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*7)+6, r1->fields[5], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*7)+7, r1->fields[6], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx==31) { SAFE_SQLITE3_STEP2(statement32); rc=(*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc=(*proxy_sqlite3_bind_int64)(statement1, 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 5, atoi(r1->fields[4])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 6, r1->fields[5], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 7, r1->fields[6], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); } } void ProxySQL_Admin::save_pgsql_firewall_whitelist_rules_from_runtime(bool _runtime, SQLite3_result* resultset) { // NOTE: this function doesn't delete resultset. The caller must do it if (resultset) { int rc; sqlite3_stmt* statement1 = NULL; sqlite3_stmt* statement32 = NULL; char* query1 = NULL; char* query32 = NULL; std::string query32s = ""; if (_runtime) { query1 = (char*)"INSERT INTO runtime_pgsql_firewall_whitelist_rules VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"; query32s = "INSERT INTO runtime_pgsql_firewall_whitelist_rules VALUES " + generate_multi_rows_query(32, 7); query32 = (char*)query32s.c_str(); } else { query1 = (char*)"INSERT INTO pgsql_firewall_whitelist_rules VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"; query32s = "INSERT INTO pgsql_firewall_whitelist_rules VALUES " + generate_multi_rows_query(32, 7); query32 = (char*)query32s.c_str(); } rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, admindb); int row_idx = 0; int max_bulk_row_idx = resultset->rows_count / 32; max_bulk_row_idx = max_bulk_row_idx * 32; for (std::vector::iterator it = resultset->rows.begin(); it != resultset->rows.end(); ++it) { SQLite3_row* r1 = *it; int idx = row_idx % 32; if (row_idx < max_bulk_row_idx) { // bulk rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 7) + 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 7) + 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 7) + 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 7) + 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 7) + 5, atoi(r1->fields[4])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 7) + 6, r1->fields[5], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 7) + 7, r1->fields[6], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx == 31) { SAFE_SQLITE3_STEP2(statement32); rc = (*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc = (*proxy_sqlite3_bind_int64)(statement1, 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 5, atoi(r1->fields[4])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 6, r1->fields[5], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 7, r1->fields[6], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); } } void ProxySQL_Admin::save_mysql_firewall_from_runtime(bool _runtime) { unsigned long long curtime1=monotonic_time(); if (_runtime) { admindb->execute("DELETE FROM runtime_mysql_firewall_whitelist_rules"); admindb->execute("DELETE FROM runtime_mysql_firewall_whitelist_users"); admindb->execute("DELETE FROM runtime_mysql_firewall_whitelist_sqli_fingerprints"); } else { admindb->execute("DELETE FROM mysql_firewall_whitelist_rules"); admindb->execute("DELETE FROM mysql_firewall_whitelist_users"); admindb->execute("DELETE FROM mysql_firewall_whitelist_sqli_fingerprints"); } SQLite3_result * resultset_rules = NULL; SQLite3_result * resultset_users = NULL; SQLite3_result * resultset_sqli_fingerprints = NULL; GloMyQPro->get_current_firewall_whitelist(&resultset_users, &resultset_rules, &resultset_sqli_fingerprints); if (resultset_users) { save_mysql_firewall_whitelist_users_from_runtime(_runtime, resultset_users); delete resultset_users; } if (resultset_rules) { save_mysql_firewall_whitelist_rules_from_runtime(_runtime, resultset_rules); delete resultset_rules; } if (resultset_sqli_fingerprints) { save_mysql_firewall_whitelist_sqli_fingerprints_from_runtime(_runtime, resultset_sqli_fingerprints); delete resultset_sqli_fingerprints; } unsigned long long curtime2=monotonic_time(); curtime1 = curtime1/1000; curtime2 = curtime2/1000; if (curtime2-curtime1 > 1000) { proxy_info("locked for %llums\n", curtime2-curtime1); } } void ProxySQL_Admin::save_pgsql_firewall_from_runtime(bool _runtime) { unsigned long long curtime1 = monotonic_time(); if (_runtime) { admindb->execute("DELETE FROM runtime_pgsql_firewall_whitelist_rules"); admindb->execute("DELETE FROM runtime_pgsql_firewall_whitelist_users"); admindb->execute("DELETE FROM runtime_pgsql_firewall_whitelist_sqli_fingerprints"); } else { admindb->execute("DELETE FROM pgsql_firewall_whitelist_rules"); admindb->execute("DELETE FROM pgsql_firewall_whitelist_users"); admindb->execute("DELETE FROM pgsql_firewall_whitelist_sqli_fingerprints"); } SQLite3_result* resultset_rules = NULL; SQLite3_result* resultset_users = NULL; SQLite3_result* resultset_sqli_fingerprints = NULL; GloPgQPro->get_current_firewall_whitelist(&resultset_users, &resultset_rules, &resultset_sqli_fingerprints); if (resultset_users) { save_pgsql_firewall_whitelist_users_from_runtime(_runtime, resultset_users); delete resultset_users; } if (resultset_rules) { save_pgsql_firewall_whitelist_rules_from_runtime(_runtime, resultset_rules); delete resultset_rules; } if (resultset_sqli_fingerprints) { save_pgsql_firewall_whitelist_sqli_fingerprints_from_runtime(_runtime, resultset_sqli_fingerprints); delete resultset_sqli_fingerprints; } unsigned long long curtime2 = monotonic_time(); curtime1 = curtime1 / 1000; curtime2 = curtime2 / 1000; if (curtime2 - curtime1 > 1000) { proxy_info("locked for %llums\n", curtime2 - curtime1); } } #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 */ #ifdef DEBUG int ProxySQL_Admin::load_debug_to_runtime() { int numrows = flush_debug_levels_database_to_runtime(admindb); if (numrows) { // so far so good // we now load filters flush_debug_filters_database_to_runtime(admindb); } return numrows; } // because debug_mutex is static in debug.cpp // we get a list of filters debug, where a copy constructor is called // it is not optimal in term of performance, but this is not critical void ProxySQL_Admin::flush_debug_filters_runtime_to_database(SQLite3DB *db) { std::set filters; proxy_debug_get_filters(filters); admindb->execute((char *)"DELETE FROM debug_filters"); for (std::set::iterator it = filters.begin(); it != filters.end(); ++it) { // we are splitting each key in 3 parts, separated by : // we call c_split_2 twice char *a = NULL; char *b = NULL; char *c = NULL; std::string s = *it; char *key = strdup(s.c_str()); c_split_2(key, (const char *)":", &a, &b); assert(a); assert(b); free(b); b = NULL; c_split_2(index(key,':')+1, (const char *)":", &b, &c); assert(b); assert(c); std::string query = "INSERT INTO debug_filters VALUES ('"; query += a; query += "',"; query += b; // line query += ",'"; query += c; // funct query += "')"; admindb->execute(query.c_str()); free(a); free(b); free(c); free(key); } } void ProxySQL_Admin::save_debug_from_runtime() { flush_debug_levels_runtime_to_database(admindb, true); flush_debug_filters_runtime_to_database(admindb); } // because debug_mutex is static in debug.cpp // we generate a set and sent it to debug, where a copy constructor is called // it is not optimal in term of performance, but this is not critical void ProxySQL_Admin::flush_debug_filters_database_to_runtime(SQLite3DB *db) { char *error=NULL; int cols=0; int affected_rows=0; SQLite3_result *resultset=NULL; std::string query = "SELECT filename, line, funct FROM debug_filters"; admindb->execute_statement(query.c_str(), &error , &cols , &affected_rows , &resultset); if (error) { // LCOV_EXCL_START proxy_error("Error on %s : %s\n", query.c_str(), error); assert(0); // LCOV_EXCL_STOP } else { std::set filters; for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; std::string key; // we create a string with the row // remember the format is filename:line:funct // no column can be null key = r->fields[0]; key += ":"; key += r->fields[1]; key += ":"; key += r->fields[2]; filters.emplace(key); } proxy_debug_load_filters(filters); } if (resultset) delete resultset; } int ProxySQL_Admin::flush_debug_levels_database_to_runtime(SQLite3DB *db) { int i; char *query=(char *)"SELECT verbosity FROM debug_levels WHERE module=\"%s\""; int l=strlen(query)+100; int rownum=0; int result; sqlite3 *_db=db->get_db(); for (i=0;iexecute("PRAGMA foreign_keys = OFF"); BQE1(admindb, mysql_servers_tablenames, "", "INSERT OR REPLACE INTO main.", " SELECT * FROM disk."); BQE1(admindb, mysql_query_rules_tablenames, "", "INSERT OR REPLACE INTO main.", " SELECT * FROM disk."); admindb->execute("INSERT OR REPLACE INTO main.mysql_users SELECT * FROM disk.mysql_users"); BQE1(admindb, mysql_firewall_tablenames, "", "INSERT OR REPLACE INTO main.", " SELECT * FROM disk."); BQE1(admindb, pgsql_servers_tablenames, "", "INSERT OR REPLACE INTO main.", " SELECT * FROM disk."); BQE1(admindb, pgsql_query_rules_tablenames, "", "INSERT OR REPLACE INTO main.", " SELECT * FROM disk."); admindb->execute("INSERT OR REPLACE INTO main.pgsql_users SELECT * FROM disk.pgsql_users"); BQE1(admindb, pgsql_firewall_tablenames, "", "INSERT OR REPLACE INTO main.", " SELECT * FROM disk."); { // online upgrade of mysql-session_idle_ms char *error=NULL; int cols=0; int affected_rows=0; SQLite3_result *resultset=NULL; std::string q = "SELECT variable_value FROM disk.global_variables WHERE variable_name=\"mysql-session_idle_ms\""; admindb->execute_statement(q.c_str(), &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", q.c_str(), error); } else { if (resultset->rows_count == 1) { SQLite3_row *r = resultset->rows[0]; if (strcmp(r->fields[0], "1000") == 0) { proxy_warning("Detected mysql-session_idle_ms=1000 : automatically setting it to 1 assuming this is an upgrade from an older version.\n"); proxy_warning("Benchmarks and users show that the old default (1000) of mysql-session_idle_ms is not optimal.\n"); proxy_warning("This release prevents the value of mysql-session_idle_ms to be 1000.\n"); proxy_warning("If you really want to set mysql-session_idle_ms close to 1000 , it is recommended to set it to a closer value like 999 or 1001\n"); admindb->execute("UPDATE disk.global_variables SET variable_value=\"1\" WHERE variable_name=\"mysql-session_idle_ms\""); } } } if (resultset) delete resultset; } { // online upgrade of mysql-session_idle_ms char* error = NULL; int cols = 0; int affected_rows = 0; SQLite3_result* resultset = NULL; std::string q = "SELECT variable_value FROM disk.global_variables WHERE variable_name=\"pgsql-session_idle_ms\""; admindb->execute_statement(q.c_str(), &error, &cols, &affected_rows, &resultset); if (error) { proxy_error("Error on %s : %s\n", q.c_str(), error); } else { if (resultset->rows_count == 1) { SQLite3_row* r = resultset->rows[0]; if (strcmp(r->fields[0], "1000") == 0) { proxy_warning("Detected pgsql-session_idle_ms=1000 : automatically setting it to 1 assuming this is an upgrade from an older version.\n"); proxy_warning("Benchmarks and users show that the old default (1000) of pgsql-session_idle_ms is not optimal.\n"); proxy_warning("This release prevents the value of pgsql-session_idle_ms to be 1000.\n"); proxy_warning("If you really want to set pgsql-session_idle_ms close to 1000 , it is recommended to set it to a closer value like 999 or 1001\n"); admindb->execute("UPDATE disk.global_variables SET variable_value=\"1\" WHERE variable_name=\"pgsql-session_idle_ms\""); } } } if (resultset) delete resultset; } admindb->execute("INSERT OR REPLACE INTO main.global_variables SELECT * FROM disk.global_variables"); BQE1(admindb, scheduler_tablenames, "", "INSERT OR REPLACE INTO main.", " SELECT * FROM disk."); BQE1(admindb, restapi_tablenames, "", "INSERT OR REPLACE INTO main.", " SELECT * FROM disk."); BQE1(admindb, proxysql_servers_tablenames, "", "INSERT OR REPLACE INTO main.", " SELECT * FROM disk."); #ifdef DEBUG admindb->execute("INSERT OR REPLACE INTO main.debug_levels SELECT * FROM disk.debug_levels"); admindb->execute("INSERT OR REPLACE INTO main.debug_filters SELECT * FROM disk.debug_filters"); #endif /* DEBUG */ #ifdef PROXYSQLCLICKHOUSE if ( GloVars.global.clickhouse_server == true ) { admindb->execute("INSERT OR REPLACE INTO main.clickhouse_users SELECT * FROM disk.clickhouse_users"); } #endif /* PROXYSQLCLICKHOUSE */ admindb->execute("PRAGMA foreign_keys = ON"); #if defined(TEST_AURORA) || defined(TEST_GALERA) admindb->execute("DELETE FROM mysql_servers WHERE gtid_port > 0"); // temporary disable add GTID checks #endif if (GloMyLdapAuth) { admindb->execute("INSERT OR REPLACE INTO main.mysql_ldap_mapping SELECT * FROM disk.mysql_ldap_mapping"); } } void ProxySQL_Admin::__insert_or_replace_disktable_select_maintable() { BQE1(admindb, mysql_servers_tablenames, "", "INSERT OR REPLACE INTO disk.", " SELECT * FROM main."); BQE1(admindb, mysql_query_rules_tablenames, "", "INSERT OR REPLACE INTO disk.", " SELECT * FROM main."); admindb->execute("INSERT OR REPLACE INTO disk.mysql_users SELECT * FROM main.mysql_users"); BQE1(admindb, mysql_firewall_tablenames, "", "INSERT OR REPLACE INTO disk.", " SELECT * FROM main."); admindb->execute("INSERT OR REPLACE INTO disk.global_variables SELECT * FROM main.global_variables"); BQE1(admindb, scheduler_tablenames, "", "INSERT OR REPLACE INTO disk.", " SELECT * FROM main."); BQE1(admindb, restapi_tablenames, "", "INSERT OR REPLACE INTO disk.", " SELECT * FROM main."); BQE1(admindb, proxysql_servers_tablenames, "", "INSERT OR REPLACE INTO disk.", " SELECT * FROM main."); BQE1(admindb, pgsql_servers_tablenames, "", "INSERT OR REPLACE INTO disk.", " SELECT * FROM main."); BQE1(admindb, pgsql_query_rules_tablenames, "", "INSERT OR REPLACE INTO disk.", " SELECT * FROM main."); admindb->execute("INSERT OR REPLACE INTO disk.pgsql_users SELECT * FROM main.pgsql_users"); BQE1(admindb, pgsql_firewall_tablenames, "", "INSERT OR REPLACE INTO disk.", " SELECT * FROM main."); #ifdef DEBUG admindb->execute("INSERT OR REPLACE INTO disk.debug_levels SELECT * FROM main.debug_levels"); admindb->execute("INSERT OR REPLACE INTO disk.debug_filters SELECT * FROM main.debug_filters"); #endif /* DEBUG */ #ifdef PROXYSQLCLICKHOUSE if ( GloVars.global.clickhouse_server == true ) { admindb->execute("INSERT OR REPLACE INTO disk.clickhouse_users SELECT * FROM main.clickhouse_users"); } #endif /* PROXYSQLCLICKHOUSE */ if (GloMyLdapAuth) { admindb->execute("INSERT OR REPLACE INTO disk.mysql_ldap_mapping SELECT * FROM main.mysql_ldap_mapping"); } } void ProxySQL_Admin::flush_mysql_users__from_disk_to_memory() { admindb->wrlock(); admindb->execute("PRAGMA foreign_keys = OFF"); admindb->execute("DELETE FROM main.mysql_users"); admindb->execute("INSERT INTO main.mysql_users SELECT * FROM disk.mysql_users"); if (GloMyLdapAuth) { admindb->execute("DELETE FROM main.mysql_ldap_mapping"); admindb->execute("INSERT INTO main.mysql_ldap_mapping SELECT * FROM disk.mysql_ldap_mapping"); } admindb->execute("PRAGMA foreign_keys = ON"); admindb->wrunlock(); } void ProxySQL_Admin::flush_mysql_users__from_memory_to_disk() { admindb->wrlock(); admindb->execute("PRAGMA foreign_keys = OFF"); admindb->execute("DELETE FROM disk.mysql_users"); admindb->execute("INSERT INTO disk.mysql_users SELECT * FROM main.mysql_users"); if (GloMyLdapAuth) { admindb->execute("DELETE FROM disk.mysql_ldap_mapping"); admindb->execute("INSERT INTO disk.mysql_ldap_mapping SELECT * FROM main.mysql_ldap_mapping"); } admindb->execute("PRAGMA foreign_keys = ON"); admindb->wrunlock(); } void ProxySQL_Admin::flush_pgsql_users__from_memory_to_disk() { admindb->wrlock(); admindb->execute("PRAGMA foreign_keys = OFF"); admindb->execute("DELETE FROM disk.pgsql_users"); admindb->execute("INSERT INTO disk.pgsql_users SELECT * FROM main.pgsql_users"); if (GloMyLdapAuth) { admindb->execute("DELETE FROM disk.pgsql_ldap_mapping"); admindb->execute("INSERT INTO disk.pgsql_ldap_mapping SELECT * FROM main.pgsql_ldap_mapping"); } admindb->execute("PRAGMA foreign_keys = ON"); admindb->wrunlock(); } void ProxySQL_Admin::flush_pgsql_users__from_disk_to_memory() { admindb->wrlock(); admindb->execute("PRAGMA foreign_keys = OFF"); admindb->execute("DELETE FROM main.pgsql_users"); admindb->execute("INSERT INTO main.pgsql_users SELECT * FROM disk.pgsql_users"); if (GloMyLdapAuth) { admindb->execute("DELETE FROM main.pgsql_ldap_mapping"); admindb->execute("INSERT INTO main.pgsql_ldap_mapping SELECT * FROM disk.pgsql_ldap_mapping"); } admindb->execute("PRAGMA foreign_keys = ON"); admindb->wrunlock(); } #ifdef PROXYSQLCLICKHOUSE void ProxySQL_Admin::flush_clickhouse_users__from_disk_to_memory() { admindb->wrlock(); admindb->execute("PRAGMA foreign_keys = OFF"); admindb->execute("DELETE FROM main.clickhouse_users"); admindb->execute("INSERT INTO main.clickhouse_users SELECT * FROM disk.clickhouse_users"); admindb->execute("PRAGMA foreign_keys = ON"); admindb->wrunlock(); } void ProxySQL_Admin::flush_clickhouse_users__from_memory_to_disk() { admindb->wrlock(); admindb->execute("PRAGMA foreign_keys = OFF"); admindb->execute("DELETE FROM disk.clickhouse_users"); admindb->execute("INSERT INTO disk.clickhouse_users SELECT * FROM main.clickhouse_users"); admindb->execute("PRAGMA foreign_keys = ON"); admindb->wrunlock(); } #endif /* PROXYSQLCLICKHOUSE */ void ProxySQL_Admin::flush_GENERIC__from_to(const string& name, const string& direction) { assert(direction == "disk_to_memory" || direction == "memory_to_disk"); admindb->wrlock(); admindb->execute("PRAGMA foreign_keys = OFF"); auto it = module_tablenames.find(name); assert(it != module_tablenames.end()); if (direction == "disk_to_memory") { BQE1(admindb, it->second, "DELETE FROM main.", "INSERT INTO main.", " SELECT * FROM disk."); } else if (direction == "memory_to_disk") { BQE1(admindb, it->second, "DELETE FROM disk.", "INSERT INTO disk.", " SELECT * FROM main."); } else { assert(0); } admindb->execute("PRAGMA foreign_keys = ON"); admindb->wrunlock(); } void ProxySQL_Admin::flush_mysql_variables__from_memory_to_disk() { admindb->wrlock(); admindb->execute("PRAGMA foreign_keys = OFF"); admindb->execute("INSERT OR REPLACE INTO disk.global_variables SELECT * FROM main.global_variables WHERE variable_name LIKE 'mysql-%'"); admindb->execute("PRAGMA foreign_keys = ON"); admindb->wrunlock(); } void ProxySQL_Admin::flush_admin_variables__from_memory_to_disk() { admindb->wrlock(); admindb->execute("PRAGMA foreign_keys = OFF"); admindb->execute("INSERT OR REPLACE INTO disk.global_variables SELECT * FROM main.global_variables WHERE variable_name LIKE 'admin-%'"); admindb->execute("PRAGMA foreign_keys = ON"); admindb->wrunlock(); } void ProxySQL_Admin::flush_ldap_variables__from_memory_to_disk() { admindb->wrlock(); admindb->execute("PRAGMA foreign_keys = OFF"); admindb->execute("INSERT OR REPLACE INTO disk.global_variables SELECT * FROM main.global_variables WHERE variable_name LIKE 'ldap-%'"); admindb->execute("PRAGMA foreign_keys = ON"); admindb->wrunlock(); } 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 ProxySQL_Admin::init_users( unique_ptr&& mysql_users_resultset, const std::string& checksum, const time_t epoch ) { pthread_mutex_lock(&users_mutex); __refresh_users(std::move(mysql_users_resultset), checksum, epoch); pthread_mutex_unlock(&users_mutex); } void ProxySQL_Admin::init_pgsql_users( unique_ptr&& pgsql_users_resultset, const std::string& checksum, const time_t epoch ) { pthread_mutex_lock(&users_mutex); __refresh_pgsql_users(std::move(pgsql_users_resultset), checksum, epoch); pthread_mutex_unlock(&users_mutex); } #ifdef PROXYSQLCLICKHOUSE void ProxySQL_Admin::init_clickhouse_users() { pthread_mutex_lock(&users_mutex); __refresh_clickhouse_users(); pthread_mutex_unlock(&users_mutex); } #endif /* PROXYSQLCLICKHOUSE */ void ProxySQL_Admin::init_mysql_servers() { mysql_servers_wrlock(); load_mysql_servers_to_runtime(); mysql_servers_wrunlock(); } void ProxySQL_Admin::init_pgsql_servers() { pgsql_servers_wrlock(); load_pgsql_servers_to_runtime(); pgsql_servers_wrunlock(); } void ProxySQL_Admin::init_proxysql_servers() { load_proxysql_servers_to_runtime(); } void ProxySQL_Admin::init_mysql_query_rules() { load_mysql_query_rules_to_runtime(); } void ProxySQL_Admin::init_mysql_firewall() { load_mysql_firewall_to_runtime(); } void ProxySQL_Admin::init_pgsql_query_rules() { load_pgsql_query_rules_to_runtime(); } void ProxySQL_Admin::init_pgsql_firewall() { load_pgsql_firewall_to_runtime(); } template void ProxySQL_Admin::add_admin_users() { #ifdef DEBUG add_credentials((char *)"admin",variables.admin_credentials, ADMIN_HOSTGROUP); add_credentials((char *)"stats",variables.stats_credentials, STATS_HOSTGROUP); #else add_credentials(variables.admin_credentials, ADMIN_HOSTGROUP); add_credentials(variables.stats_credentials, STATS_HOSTGROUP); #endif /* DEBUG */ } void ProxySQL_Admin::__refresh_users( unique_ptr&& mysql_users_resultset, const string& checksum, const time_t epoch ) { bool no_resultset_supplied = mysql_users_resultset == nullptr; // Checksums are always generated - 'admin-checksum_*' deprecated pthread_mutex_lock(&GloVars.checksum_mutex); __delete_inactive_users(USERNAME_BACKEND); __delete_inactive_users(USERNAME_FRONTEND); GloMyAuth->set_all_inactive(USERNAME_BACKEND); GloMyAuth->set_all_inactive(USERNAME_FRONTEND); add_admin_users(); SQLite3_result* added_users { __add_active_users(USERNAME_NONE, NULL, mysql_users_resultset.get()) }; if (mysql_users_resultset == nullptr && added_users != nullptr) { mysql_users_resultset.reset(added_users); } if (GloMyLdapAuth) { __add_active_users_ldap(); } GloMyAuth->remove_inactives(USERNAME_BACKEND); GloMyAuth->remove_inactives(USERNAME_FRONTEND); set_variable((char *)"admin_credentials",(char *)""); // Checksums are always generated - 'admin-checksum_*' deprecated { char* buff = nullptr; char buf[20] = { 0 }; if (no_resultset_supplied) { uint64_t hash1 = GloMyAuth->get_runtime_checksum(); if (GloMyLdapAuth) { hash1 += GloMyLdapAuth->get_ldap_mapping_runtime_checksum(); } uint32_t d32[2]; memcpy(&d32, &hash1, sizeof(hash1)); sprintf(buf,"0x%0X%0X", d32[0], d32[1]); buff = buf; } else { buff = const_cast(checksum.c_str()); } GloVars.checksums_values.mysql_users.set_checksum(buff); GloVars.checksums_values.mysql_users.version++; time_t t = time(NULL); const bool same_checksum = no_resultset_supplied == false; const bool matching_checksums = same_checksum || (GloVars.checksums_values.mysql_users.checksum == checksum); if (epoch != 0 && checksum != "" && matching_checksums) { GloVars.checksums_values.mysql_users.epoch = epoch; } else { GloVars.checksums_values.mysql_users.epoch = t; } GloVars.epoch_version = t; GloVars.generate_global_checksum(); GloVars.checksums_values.updates_cnt++; // store the new 'added_users' resultset after generating the new checksum GloMyAuth->save_mysql_users(std::move(mysql_users_resultset)); } pthread_mutex_unlock(&GloVars.checksum_mutex); proxy_info( "Computed checksum for 'LOAD MYSQL USERS TO RUNTIME' was '%s', with epoch '%llu'\n", GloVars.checksums_values.mysql_users.checksum, GloVars.checksums_values.mysql_users.epoch ); } #ifdef PROXYSQLCLICKHOUSE void ProxySQL_Admin::__refresh_clickhouse_users() { //__delete_inactive_clickhouse_users(USERNAME_BACKEND); __delete_inactive_clickhouse_users(); //GloMyAuth->set_all_inactive(USERNAME_BACKEND); GloClickHouseAuth->set_all_inactive(USERNAME_FRONTEND); //add_admin_users(); //_add_active_users(USERNAME_BACKEND); __add_active_clickhouse_users(); //GloMyAuth->remove_inactives(USERNAME_BACKEND); GloClickHouseAuth->remove_inactives(USERNAME_FRONTEND); //set_variable((char *)"admin_credentials",(char *)""); } #endif /* PROXYSQLCLICKHOUSE */ // PostgreSQL void ProxySQL_Admin::__refresh_pgsql_users( std::unique_ptr&& pgsql_users_resultset, const std::string& checksum, const time_t epoch ) { bool no_resultset_supplied = pgsql_users_resultset == nullptr; // Checksums are always generated - 'admin-checksum_*' deprecated pthread_mutex_lock(&GloVars.checksum_mutex); __delete_inactive_users(USERNAME_BACKEND); __delete_inactive_users(USERNAME_FRONTEND); GloPgAuth->set_all_inactive(USERNAME_BACKEND); GloPgAuth->set_all_inactive(USERNAME_FRONTEND); add_admin_users(); SQLite3_result* added_users{ __add_active_users(USERNAME_NONE, NULL, pgsql_users_resultset.get()) }; if (pgsql_users_resultset == nullptr && added_users != nullptr) { pgsql_users_resultset.reset(added_users); } //if (GloMyLdapAuth) { // __add_active_users_ldap(); //} GloPgAuth->remove_inactives(USERNAME_BACKEND); GloPgAuth->remove_inactives(USERNAME_FRONTEND); set_variable((char*)"admin_credentials", (char*)""); // Checksums are always generated - 'admin-checksum_*' deprecated { char* buff = nullptr; char buf[20] = { 0 }; if (no_resultset_supplied) { uint64_t hash1 = GloPgAuth->get_runtime_checksum(); //if (GloMyLdapAuth) { // hash1 += GloMyLdapAuth->get_ldap_mapping_runtime_checksum(); //} uint32_t d32[2]; memcpy(&d32, &hash1, sizeof(hash1)); sprintf(buf, "0x%0X%0X", d32[0], d32[1]); buff = buf; } else { buff = const_cast(checksum.c_str()); } GloVars.checksums_values.pgsql_users.set_checksum(buff); GloVars.checksums_values.pgsql_users.version++; time_t t = time(NULL); const bool same_checksum = no_resultset_supplied == false; const bool matching_checksums = same_checksum || (GloVars.checksums_values.pgsql_users.checksum == checksum); if (epoch != 0 && checksum != "" && matching_checksums) { GloVars.checksums_values.pgsql_users.epoch = epoch; } else { GloVars.checksums_values.pgsql_users.epoch = t; } GloVars.epoch_version = t; GloVars.generate_global_checksum(); GloVars.checksums_values.updates_cnt++; // store the new 'added_users' resultset after generating the new checksum GloPgAuth->save_pgsql_users(std::move(pgsql_users_resultset)); } pthread_mutex_unlock(&GloVars.checksum_mutex); proxy_info( "Computed checksum for 'LOAD PGSQL USERS TO RUNTIME' was '%s', with epoch '%llu'\n", GloVars.checksums_values.pgsql_users.checksum, GloVars.checksums_values.pgsql_users.epoch ); } /* * @brief Sends an OK message to a client based on the connection type. * * This function is used to send an OK message and some additional data * (number of rows or query) to the client depending on its database * management system (MySQL or PostgreSQL). * * @tparam S The type of session object passed as argument. * @param[in, out] sess A reference to a valid session object. * @param msg An OK message string that will be sent to the client. * @param rows The number of rows affected by the query for MySQL clients. * @param query The query executed for PostgreSQL clients. */ template void ProxySQL_Admin::send_ok_msg_to_client(S* sess, const char* msg, int rows, const char* query) { assert(sess->client_myds); if constexpr (std::is_same_v) { // Code for MySQL clients MySQL_Data_Stream* myds = sess->client_myds; myds->DSS = STATE_QUERY_SENT_DS; myds->myprot.generate_pkt_OK(true, NULL, NULL, 1, rows, 0, 2, 0, (char*)msg, false); myds->DSS = STATE_SLEEP; } else if constexpr (std::is_same_v) { // Code for PostgreSQL clients PgSQL_Data_Stream* myds = sess->client_myds; myds->DSS = STATE_QUERY_SENT_DS; myds->myprot.generate_ok_packet(true, true, msg, rows, query); myds->DSS = STATE_SLEEP; } else { assert(0); } } /* * @brief Sends an error message to a client based on its database management system. * * This function is used to send an error message with a given code and message * (if applicable) to the client depending on its database management system * (MySQL or PostgreSQL). * * @tparam S The type of the session object passed as argument. * @param[in, out] sess A reference to a valid session object. * @param msg An error message that will be sent to the client. * @param mysqlerrcode (For MySQL clients) The error code associated with this * error message. */ template void ProxySQL_Admin::send_error_msg_to_client(S* sess, const char *msg, uint16_t mysql_err_code /*, bool fatal*/ ) { assert(sess->client_myds); const char prefix_msg[] = "ProxySQL Admin Error: "; if constexpr (std::is_same_v) { // Code for MySQL clients MySQL_Data_Stream* myds = sess->client_myds; myds->DSS = STATE_QUERY_SENT_DS; char* new_msg = (char*)malloc(strlen(msg) + sizeof(prefix_msg)); sprintf(new_msg, "%s%s", prefix_msg, msg); myds->myprot.generate_pkt_ERR(true, NULL, NULL, 1, mysql_err_code, (char*)"28000", new_msg); free(new_msg); myds->DSS = STATE_SLEEP; } else if constexpr (std::is_same_v) { // Code for PostgreSQL clients PgSQL_Data_Stream* myds = sess->client_myds; myds->DSS = STATE_QUERY_SENT_DS; char* new_msg = (char*)malloc(strlen(msg) + sizeof(prefix_msg)); sprintf(new_msg, "%s%s", prefix_msg, msg); myds->myprot.generate_error_packet(true, true, new_msg, PGSQL_ERROR_CODES::ERRCODE_RAISE_EXCEPTION, false); free(new_msg); myds->DSS = STATE_SLEEP; } else { assert(0); } } // Explicit template instantiations for send_ok_msg_to_client and send_error_msg_to_client // These must come after the template definitions above template void ProxySQL_Admin::send_ok_msg_to_client(MySQL_Session*, char const*, int, char const*); template void ProxySQL_Admin::send_ok_msg_to_client(PgSQL_Session*, char const*, int, char const*); template void ProxySQL_Admin::send_error_msg_to_client(MySQL_Session*, char const*, unsigned short); template void ProxySQL_Admin::send_error_msg_to_client(PgSQL_Session*, char const*, unsigned short); template void ProxySQL_Admin::__delete_inactive_users(enum cred_username_type usertype) { char *error=NULL; int cols=0; int affected_rows=0; SQLite3_result *resultset=NULL; char* str = nullptr; if constexpr (pt == SERVER_TYPE_MYSQL) str=(char *)"SELECT username FROM main.mysql_users WHERE %s=1 AND active=0"; else if constexpr (pt == SERVER_TYPE_PGSQL) str = (char*)"SELECT username FROM main.pgsql_users WHERE %s=1 AND active=0"; char *query=(char *)malloc(strlen(str)+15); sprintf(query,str,(usertype==USERNAME_BACKEND ? "backend" : "frontend")); admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; if constexpr (pt == SERVER_TYPE_MYSQL) GloMyAuth->del(r->fields[0], usertype); else if constexpr (pt == SERVER_TYPE_PGSQL) GloPgAuth->del(r->fields[0], usertype); } } if (resultset) delete resultset; free(query); } #ifdef PROXYSQLCLICKHOUSE void ProxySQL_Admin::__delete_inactive_clickhouse_users() { char *error=NULL; int cols=0; int affected_rows=0; SQLite3_result *resultset=NULL; char *str=(char *)"SELECT username FROM main.mysql_users WHERE active=0"; //char *query=(char *)malloc(strlen(str)+15); //sprintf(query,str,(usertype==USERNAME_BACKEND ? "backend" : "frontend")); admindb->execute_statement(str, &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", str, error); } else { for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; GloClickHouseAuth->del(r->fields[0], USERNAME_FRONTEND); } } if (resultset) delete resultset; //free(query); } #endif /* PROXYSQLCLICKHOUSE */ void ProxySQL_Admin::__add_active_users_ldap() { if (GloMyLdapAuth==NULL) return; char *error=NULL; int cols=0; int affected_rows=0; SQLite3_result *resultset=NULL; char *query=(char *)"SELECT priority, frontend_entity, backend_entity, comment FROM mysql_ldap_mapping ORDER BY priority"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { GloMyLdapAuth->load_mysql_ldap_mapping(resultset); } if (resultset) delete resultset; resultset=NULL; } template SQLite3_result* ProxySQL_Admin::__add_active_users( enum cred_username_type usertype, char *__user, SQLite3_result* mysql_users_resultset ) { char *error=NULL; int cols=0; int affected_rows=0; SQLite3_result *resultset=NULL; char *str=NULL; char *query=NULL; if (__user==NULL) { if (mysql_users_resultset == nullptr) { if constexpr (pt == SERVER_TYPE_MYSQL) { str = (char*)"SELECT username,password,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,backend,frontend,max_connections,attributes,comment FROM main.mysql_users WHERE active=1 AND default_hostgroup>=0"; } else if constexpr (pt == SERVER_TYPE_PGSQL) { str = (char*)"SELECT username,password,use_ssl,default_hostgroup,transaction_persistent,fast_forward,backend,frontend,max_connections,attributes,comment FROM main.pgsql_users WHERE active=1 AND default_hostgroup>=0"; } admindb->execute_statement(str, &error, &cols, &affected_rows, &resultset); } else { resultset = mysql_users_resultset; } } else { if constexpr (pt == SERVER_TYPE_MYSQL) { str = (char*)"SELECT username,password,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,max_connections,attributes,comment FROM main.mysql_users WHERE %s=1 AND active=1 AND default_hostgroup>=0 AND username='%s'"; } else if constexpr (pt == SERVER_TYPE_PGSQL) { str = (char*)"SELECT username,password,use_ssl,default_hostgroup,transaction_persistent,fast_forward,max_connections,attributes,comment FROM main.pgsql_users WHERE %s=1 AND active=1 AND default_hostgroup>=0 AND username='%s'"; } query=(char *)malloc(strlen(str)+strlen(__user)+15); sprintf(query,str,(usertype==USERNAME_BACKEND ? "backend" : "frontend"),__user); admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); } SQLite3_result* added_users { nullptr }; if (error) { proxy_error("Error on %s : %s\n", query, error); } else { SQLite3_result* sqlite_result { nullptr }; if (mysql_users_resultset == nullptr) { sqlite_result = new SQLite3_result(resultset->columns); for (SQLite3_column* c : resultset->column_definition) { sqlite_result->add_column_definition(c->datatype, c->name); } } for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; char *password=NULL; if (r->fields[1]) { password=r->fields[1]; } else { password=(char *)""; } std::vector usertypes {}; char* max_connections = nullptr; char* attributes = nullptr; char* comment = nullptr; if constexpr (pt == SERVER_TYPE_MYSQL) { if (__user != nullptr) { usertypes.push_back(usertype); max_connections = r->fields[8]; attributes = r->fields[9]; comment = r->fields[10]; } else { if (strcasecmp(r->fields[8], "1") == 0) { usertypes.push_back(USERNAME_BACKEND); } if (strcasecmp(r->fields[9], "1") == 0) { usertypes.push_back(USERNAME_FRONTEND); } max_connections = r->fields[10]; attributes = r->fields[11]; comment = r->fields[12]; } } else if constexpr (pt == SERVER_TYPE_PGSQL) { if (__user != nullptr) { usertypes.push_back(usertype); max_connections = r->fields[6]; attributes = r->fields[7]; comment = r->fields[8]; } else { if (strcasecmp(r->fields[6], "1") == 0) { usertypes.push_back(USERNAME_BACKEND); } if (strcasecmp(r->fields[7], "1") == 0) { usertypes.push_back(USERNAME_FRONTEND); } max_connections = r->fields[8]; attributes = r->fields[9]; comment = r->fields[10]; } } for (const enum cred_username_type usertype : usertypes) { if constexpr (pt == SERVER_TYPE_MYSQL) { GloMyAuth->add( r->fields[0], // username password, // before #676, wewere always passing the password. Now it is possible that the password can be hashed usertype, // backend/frontend (strcmp(r->fields[2], "1") == 0 ? true : false), // use_ssl atoi(r->fields[3]), // default_hostgroup (r->fields[4] == NULL ? (char*)"" : r->fields[4]), //default_schema (strcmp(r->fields[5], "1") == 0 ? true : false), // schema_locked (strcmp(r->fields[6], "1") == 0 ? true : false), // transaction_persistent (strcmp(r->fields[7], "1") == 0 ? true : false), // fast_forward (atoi(max_connections) > 0 ? atoi(max_connections) : 0), // max_connections (attributes == NULL ? (char*)"" : attributes), // attributes (comment == NULL ? (char*)"" : comment) //comment ); } else if constexpr (pt == SERVER_TYPE_PGSQL) { GloPgAuth->add( r->fields[0], // username password, // before #676, wewere always passing the password. Now it is possible that the password can be hashed usertype, // backend/frontend (strcmp(r->fields[2], "1") == 0 ? true : false), // use_ssl atoi(r->fields[3]), // default_hostgroup (strcmp(r->fields[4], "1") == 0 ? true : false), // transaction_persistent (strcmp(r->fields[5], "1") == 0 ? true : false), // fast_forward (atoi(max_connections) > 0 ? atoi(max_connections) : 0), // max_connections (attributes == NULL ? (char*)"" : attributes), // attributes (comment == NULL ? (char*)"" : comment) //comment ); } } if (sqlite_result != nullptr) { vector pta(static_cast(resultset->columns)); for (int i = 0; i < resultset->columns; i++) { if (i == 1) { pta[i] = password; } else { if (r->fields[i] != nullptr) { pta[i] = r->fields[i]; } else { pta[i] = const_cast(""); } } } sqlite_result->add_row(&pta[0]); } } if (__user == nullptr) { if (mysql_users_resultset == nullptr) { added_users = sqlite_result; } else { added_users = mysql_users_resultset; } } // resulset has been locally allocated and must be deleted if (resultset != mysql_users_resultset) { delete resultset; } } free(query); return added_users; } #ifdef PROXYSQLCLICKHOUSE void ProxySQL_Admin::__add_active_clickhouse_users(char *__user) { char *error=NULL; int cols=0; int affected_rows=0; #ifdef ADDUSER_STMT_RAW sqlite3_stmt *statement=NULL; #else SQLite3_result *resultset=NULL; #endif char *str=NULL; char *query=NULL; if (__user==NULL) { str=(char *)"SELECT username,password,max_connections FROM main.clickhouse_users WHERE active=1"; //query=(char *)malloc(strlen(str)+15); //sprintf(query,str,(usertype==USERNAME_BACKEND ? "backend" : "frontend")); query=strdup(str); } else { str=(char *)"SELECT username,password,max_connections FROM main.clickhouse_users WHERE active=1 AND username='%s'"; query=(char *)malloc(strlen(str)+strlen(__user)+15); //sprintf(query,str,(usertype==USERNAME_BACKEND ? "backend" : "frontend"),__user); sprintf(query,str,__user); } #ifdef ADDUSER_STMT_RAW admindb->execute_statement_raw(query, &error , &cols , &affected_rows , &statement); #else admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); #endif if (error) { proxy_error("Error on %s : %s\n", query, error); } else { #ifdef ADDUSER_STMT_RAW int rc; while ((rc=(*proxy_sqlite3_step)(statement))==SQLITE_ROW) { SQLite3_row *r=new SQLite3_row(cols); r->add_fields(statement); #else for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; #endif char *password=NULL; /* // FOR CLICKHOUSE, FOR NOW WE DISABLE PASSWORD HASHING if (variables.hash_passwords) { // We must use hashed password. See issue #676 // Admin needs to hash the password if (r->fields[1] && strlen(r->fields[1])) { if (r->fields[1][0]=='*') { // the password is already hashed password=strdup(r->fields[1]); } else { // we must hash it uint8 hash_stage1[SHA_DIGEST_LENGTH]; uint8 hash_stage2[SHA_DIGEST_LENGTH]; SHA_CTX sha1_context; SHA1_Init(&sha1_context); SHA1_Update(&sha1_context, r->fields[1], strlen(r->fields[1])); SHA1_Final(hash_stage1, &sha1_context); SHA1_Init(&sha1_context); SHA1_Update(&sha1_context,hash_stage1,SHA_DIGEST_LENGTH); SHA1_Final(hash_stage2, &sha1_context); password=sha1_pass_hex((char *)hash_stage2); // note that sha1_pass_hex() returns a new buffer } } else { password=strdup((char *)""); // we also generate a new string if hash_passwords is set } } else { */ if (r->fields[1]) { password=r->fields[1]; } else { password=(char *)""; } // } GloClickHouseAuth->add( r->fields[0], // username password, // before #676, wewere always passing the password. Now it is possible that the password can be hashed USERNAME_FRONTEND, // backend/frontend false, // (strcmp(r->fields[2],"1")==0 ? true : false) , // use_ssl 0, // atoi(r->fields[3]), // default_hostgroup (char *)"", // (r->fields[4]==NULL ? (char *)"" : r->fields[4]), //default_schema false, // (strcmp(r->fields[5],"1")==0 ? true : false) , // schema_locked false, // (strcmp(r->fields[6],"1")==0 ? true : false) , // transaction_persistent false, // (strcmp(r->fields[7],"1")==0 ? true : false), // fast_forward ( atoi(r->fields[2])>0 ? atoi(r->fields[2]) : 0) // max_connections ); //if (variables.hash_passwords) { // free(password); // because we always generate a new string //} #ifdef ADDUSER_STMT_RAW delete r; #endif } } #ifdef ADDUSER_STMT_RAW if (statement) { (*proxy_sqlite3_finalize)(statement); } #else if (resultset) delete resultset; #endif free(query); } #endif /* PROXYSQLCLICKHOUSE */ void ProxySQL_Admin::dump_checksums_values_table() { int rc; pthread_mutex_lock(&GloVars.checksum_mutex); if (GloVars.checksums_values.updates_cnt == GloVars.checksums_values.dumped_at) { // exit immediately pthread_mutex_unlock(&GloVars.checksum_mutex); return; } else { GloVars.checksums_values.dumped_at = GloVars.checksums_values.updates_cnt; } char *q = (char *)"REPLACE INTO runtime_checksums_values VALUES (?1 , ?2 , ?3 , ?4)"; sqlite3_stmt *statement1 = NULL; rc = admindb->prepare_v2(q,&statement1); ASSERT_SQLITE_OK(rc, admindb); admindb->execute((char *)"BEGIN"); admindb->execute((char *)"DELETE FROM runtime_checksums_values"); rc=(*proxy_sqlite3_bind_text)(statement1, 1, "admin_variables", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.admin_variables.version); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.admin_variables.epoch); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.admin_variables.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 1, "mysql_query_rules", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.mysql_query_rules.version); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.mysql_query_rules.epoch); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.mysql_query_rules.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 1, "mysql_servers", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.mysql_servers.version); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.mysql_servers.epoch); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.mysql_servers.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 1, "mysql_users", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.mysql_users.version); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.mysql_users.epoch); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.mysql_users.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 1, "mysql_variables", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.mysql_variables.version); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.mysql_variables.epoch); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.mysql_variables.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 1, "proxysql_servers", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.proxysql_servers.version); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.proxysql_servers.epoch); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.proxysql_servers.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 1, "mysql_servers_v2", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.mysql_servers_v2.version); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.mysql_servers_v2.epoch); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.mysql_servers_v2.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); //PostgreSQL rc = (*proxy_sqlite3_bind_text)(statement1, 1, "pgsql_query_rules", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.pgsql_query_rules.version); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.pgsql_query_rules.epoch); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.pgsql_query_rules.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 1, "pgsql_servers", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.pgsql_servers.version); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.pgsql_servers.epoch); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.pgsql_servers.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 1, "pgsql_users", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.pgsql_users.version); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.pgsql_users.epoch); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.pgsql_users.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 1, "pgsql_variables", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.pgsql_variables.version); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.pgsql_variables.epoch); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.pgsql_variables.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); // if (GloMyLdapAuth) { rc=(*proxy_sqlite3_bind_text)(statement1, 1, "ldap_variables", -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 2, GloVars.checksums_values.ldap_variables.version); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, GloVars.checksums_values.ldap_variables.epoch); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, GloVars.checksums_values.ldap_variables.checksum, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } admindb->execute((char *)"COMMIT"); pthread_mutex_unlock(&GloVars.checksum_mutex); (*proxy_sqlite3_finalize)(statement1); } void ProxySQL_Admin::save_mysql_users_runtime_to_database(bool _runtime) { char *query=NULL; if (_runtime) { query=(char *)"DELETE FROM main.runtime_mysql_users"; admindb->execute(query); } else { char *qd=(char *)"UPDATE mysql_users SET active=0"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", qd); admindb->execute(qd); } account_details_t **ads=NULL; int num_users; int i; int rc; char *qf_stmt1=(char *)"REPLACE INTO mysql_users(username,password,active,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,backend,frontend,max_connections,attributes,comment) VALUES(?1,?2,1,?3,?4,?5,?6,?7,?8,0,1,?9,?10,?11)"; char *qb_stmt1=(char *)"REPLACE INTO mysql_users(username,password,active,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,backend,frontend,max_connections,attributes,comment) VALUES(?1,?2,1,?3,?4,?5,?6,?7,?8,1,0,?9,?10,?11)"; char *qfr_stmt1=(char *)"REPLACE INTO runtime_mysql_users(username,password,active,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,backend,frontend,max_connections,attributes,comment) VALUES(?1,?2,1,?3,?4,?5,?6,?7,?8,0,1,?9,?10,?11)"; char *qbr_stmt1=(char *)"REPLACE INTO runtime_mysql_users(username,password,active,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,backend,frontend,max_connections,attributes,comment) VALUES(?1,?2,1,?3,?4,?5,?6,?7,?8,1,0,?9,?10,?11)"; num_users=GloMyAuth->dump_all_users(&ads); if (num_users==0) return; char *q_stmt1_f=NULL; char *q_stmt1_b=NULL; sqlite3_stmt *f_statement1=NULL; sqlite3_stmt *b_statement1=NULL; if (_runtime) { q_stmt1_f=qfr_stmt1; q_stmt1_b=qbr_stmt1; } else { q_stmt1_f=qf_stmt1; q_stmt1_b=qb_stmt1; } rc = admindb->prepare_v2(q_stmt1_f, &f_statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(q_stmt1_b, &b_statement1); ASSERT_SQLITE_OK(rc, admindb); for (i=0; idefault_hostgroup >= 0) { if (ad->__frontend) { statement1=f_statement1; } else { statement1=b_statement1; } rc=(*proxy_sqlite3_bind_text)(statement1, 1, ad->username, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 2, ad->password, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, ad->use_ssl); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 4, ad->default_hostgroup); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 5, ad->default_schema, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 6, ad->schema_locked); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 7, ad->transaction_persistent); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 8, ad->fast_forward); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 9, ad->max_connections); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 10, ad->attributes, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 11, ad->comment, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } free(ad->username); free(ad->password); // this is not initialized with dump_all_users( , false) free(ad->default_schema); // this is not initialized with dump_all_users( , false) free(ad->comment); free(ad->attributes); free(ad); } (*proxy_sqlite3_finalize)(f_statement1); (*proxy_sqlite3_finalize)(b_statement1); free(ads); } void ProxySQL_Admin::save_pgsql_users_runtime_to_database(bool _runtime) { char* query = NULL; if (_runtime) { query = (char*)"DELETE FROM main.runtime_pgsql_users"; admindb->execute(query); } else { char* qd = (char*)"UPDATE pgsql_users SET active=0"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", qd); admindb->execute(qd); } pgsql_account_details_t** ads = NULL; int num_users; int i; int rc; // char *qf=(char *)"REPLACE INTO pgsql_users(username,password,active,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,backend,frontend,max_connections) VALUES('%s','%s',1,%d,%d,'%s',%d,%d,%d,COALESCE((SELECT backend FROM mysql_users WHERE username='%s' AND frontend=1),0),1,%d)"; // char *qb=(char *)"REPLACE INTO pgsql_users(username,password,active,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,backend,frontend,max_connections) VALUES('%s','%s',1,%d,%d,'%s',%d,%d,%d,1,COALESCE((SELECT frontend FROM mysql_users WHERE username='%s' AND backend=1),0),%d)"; // char *qfr=(char *)"REPLACE INTO runtime_pgsql_users(username,password,active,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,backend,frontend,max_connections) VALUES('%s','%s',1,%d,%d,'%s',%d,%d,%d,COALESCE((SELECT backend FROM runtime_mysql_users WHERE username='%s' AND frontend=1),0),1,%d)"; // char *qbr=(char *)"REPLACE INTO runtime_pgsql_users(username,password,active,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,backend,frontend,max_connections) VALUES('%s','%s',1,%d,%d,'%s',%d,%d,%d,1,COALESCE((SELECT frontend FROM runtime_mysql_users WHERE username='%s' AND backend=1),0),%d)"; char* qf_stmt1 = (char*)"REPLACE INTO pgsql_users(username,password,active,use_ssl,default_hostgroup,transaction_persistent,fast_forward,backend,frontend,max_connections,attributes,comment) VALUES(?1,?2,1,?3,?4,?5,?6,0,1,?7,?8,?9)"; char* qb_stmt1 = (char*)"REPLACE INTO pgsql_users(username,password,active,use_ssl,default_hostgroup,transaction_persistent,fast_forward,backend,frontend,max_connections,attributes,comment) VALUES(?1,?2,1,?3,?4,?5,?6,1,0,?7,?8,?9)"; char* qfr_stmt1 = (char*)"REPLACE INTO runtime_pgsql_users(username,password,active,use_ssl,default_hostgroup,transaction_persistent,fast_forward,backend,frontend,max_connections,attributes,comment) VALUES(?1,?2,1,?3,?4,?5,?6,0,1,?7,?8,?9)"; char* qbr_stmt1 = (char*)"REPLACE INTO runtime_pgsql_users(username,password,active,use_ssl,default_hostgroup,transaction_persistent,fast_forward,backend,frontend,max_connections,attributes,comment) VALUES(?1,?2,1,?3,?4,?5,?6,1,0,?7,?8,?9)"; num_users = GloPgAuth->dump_all_users(&ads); if (num_users == 0) return; char* q_stmt1_f = NULL; char* q_stmt1_b = NULL; sqlite3_stmt* f_statement1 = NULL; sqlite3_stmt* b_statement1 = NULL; //sqlite3 *mydb3=admindb->get_db(); if (_runtime) { q_stmt1_f = qfr_stmt1; q_stmt1_b = qbr_stmt1; } else { q_stmt1_f = qf_stmt1; q_stmt1_b = qb_stmt1; } //rc=(*proxy_sqlite3_prepare_v2)(mydb3, q_stmt1_f, -1, &f_statement1, 0); rc = admindb->prepare_v2(q_stmt1_f, &f_statement1); ASSERT_SQLITE_OK(rc, admindb); //rc=(*proxy_sqlite3_prepare_v2)(mydb3, q_stmt1_b, -1, &b_statement1, 0); rc = admindb->prepare_v2(q_stmt1_b, &b_statement1); ASSERT_SQLITE_OK(rc, admindb); for (i = 0; i < num_users; i++) { //fprintf(stderr,"%s %d\n", ads[i]->username, ads[i]->default_hostgroup); pgsql_account_details_t* ad = ads[i]; sqlite3_stmt* statement1 = NULL; if (ads[i]->default_hostgroup >= 0) { /* char *q=NULL; if (_runtime==false) { if (ad->__frontend) { q=qf; } else { q=qb; } } else { // _runtime==true if (ad->__frontend) { q=qfr; statement1=f_statement1; } else { q=qbr; statement1=b_statement1; } } */ if (ad->__frontend) { statement1 = f_statement1; } else { statement1 = b_statement1; } /* if (_runtime==false) { query=(char *)malloc(strlen(q)+strlen(ad->username)*2+strlen(ad->password)+strlen(ad->default_schema)+256); sprintf(query, q, ad->username, ad->password, ad->use_ssl, ad->default_hostgroup, ad->default_schema, ad->schema_locked, ad->transaction_persistent, ad->fast_forward, ad->username, ad->max_connections); //fprintf(stderr,"%s\n",query); proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); free(query); } else { */ rc = (*proxy_sqlite3_bind_text)(statement1, 1, ad->username, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 2, ad->password, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 3, ad->use_ssl); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 4, ad->default_hostgroup); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 5, ad->transaction_persistent); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 6, ad->fast_forward); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 7, ad->max_connections); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 8, ad->attributes, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 9, ad->comment, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } free(ad->username); free(ad->password); // this is not initialized with dump_all_users( , false) free(ad->comment); free(ad->attributes); free(ad); } if (_runtime) { (*proxy_sqlite3_finalize)(f_statement1); (*proxy_sqlite3_finalize)(b_statement1); } free(ads); } void ProxySQL_Admin::save_mysql_ldap_mapping_runtime_to_database(bool _runtime) { if (GloMyLdapAuth==NULL) { return; } char *query=NULL; SQLite3_result *resultset=NULL; if (_runtime) { query=(char *)"DELETE FROM main.runtime_mysql_ldap_mapping"; } else { query=(char *)"DELETE FROM main.mysql_ldap_mapping"; } proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); resultset=GloMyLdapAuth->dump_table_mysql_ldap_mapping(); if (resultset) { int rc; sqlite3_stmt *statement1=NULL; sqlite3_stmt *statement8=NULL; //sqlite3 *mydb3=admindb->get_db(); char *query1=NULL; char *query8=NULL; std::string query8s = ""; if (_runtime) { query1=(char *)"INSERT INTO runtime_mysql_ldap_mapping VALUES (?1, ?2, ?3, ?4)"; query8s = "INSERT INTO runtime_mysql_ldap_mapping VALUES " + generate_multi_rows_query(8,4); query8 = (char *)query8s.c_str(); } else { query1=(char *)"INSERT INTO mysql_ldap_mapping VALUES (?1, ?2, ?3, ?4)"; query8s = "INSERT INTO mysql_ldap_mapping VALUES " + generate_multi_rows_query(8,4); query8 = (char *)query8s.c_str(); } rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(query8, &statement8); ASSERT_SQLITE_OK(rc, admindb); int row_idx=0; int max_bulk_row_idx=resultset->rows_count/8; max_bulk_row_idx=max_bulk_row_idx*8; for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r1=*it; int idx=row_idx%8; if (row_idxfields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement8, (idx*7)+2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement8, (idx*7)+3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement8, (idx*7)+4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx==7) { SAFE_SQLITE3_STEP2(statement8); rc=(*proxy_sqlite3_clear_bindings)(statement8); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement8); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc=(*proxy_sqlite3_bind_int64)(statement1, 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement8); } if(resultset) delete resultset; resultset=NULL; } void ProxySQL_Admin::save_pgsql_ldap_mapping_runtime_to_database(bool _runtime) { if (GloMyLdapAuth == NULL) { return; } char* query = NULL; SQLite3_result* resultset = NULL; if (_runtime) { query = (char*)"DELETE FROM main.runtime_pgsql_ldap_mapping"; } else { query = (char*)"DELETE FROM main.pgsql_ldap_mapping"; } proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); resultset = GloMyLdapAuth->dump_table_pgsql_ldap_mapping(); if (resultset) { int rc; sqlite3_stmt* statement1 = NULL; sqlite3_stmt* statement8 = NULL; //sqlite3 *mydb3=admindb->get_db(); char* query1 = NULL; char* query8 = NULL; std::string query8s = ""; if (_runtime) { query1 = (char*)"INSERT INTO runtime_pgsql_ldap_mapping VALUES (?1, ?2, ?3, ?4)"; query8s = "INSERT INTO runtime_pgsql_ldap_mapping VALUES " + generate_multi_rows_query(8, 4); query8 = (char*)query8s.c_str(); } else { query1 = (char*)"INSERT INTO pgsql_ldap_mapping VALUES (?1, ?2, ?3, ?4)"; query8s = "INSERT INTO pgsql_ldap_mapping VALUES " + generate_multi_rows_query(8, 4); query8 = (char*)query8s.c_str(); } //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query1, -1, &statement1, 0); rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query8, -1, &statement8, 0); rc = admindb->prepare_v2(query8, &statement8); ASSERT_SQLITE_OK(rc, admindb); int row_idx = 0; int max_bulk_row_idx = resultset->rows_count / 8; max_bulk_row_idx = max_bulk_row_idx * 8; for (std::vector::iterator it = resultset->rows.begin(); it != resultset->rows.end(); ++it) { SQLite3_row* r1 = *it; int idx = row_idx % 8; if (row_idx < max_bulk_row_idx) { // bulk rc = (*proxy_sqlite3_bind_int64)(statement8, (idx * 7) + 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement8, (idx * 7) + 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement8, (idx * 7) + 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement8, (idx * 7) + 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx == 7) { SAFE_SQLITE3_STEP2(statement8); rc = (*proxy_sqlite3_clear_bindings)(statement8); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement8); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc = (*proxy_sqlite3_bind_int64)(statement1, 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement8); } if (resultset) delete resultset; resultset = NULL; } #ifdef PROXYSQLCLICKHOUSE void ProxySQL_Admin::save_clickhouse_users_runtime_to_database(bool _runtime) { int rc; char *query=NULL; if (_runtime) { query=(char *)"DELETE FROM main.runtime_clickhouse_users"; admindb->execute(query); } else { char *qd=(char *)"UPDATE clickhouse_users SET active=0"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", qd); admindb->execute(qd); } ch_account_details_t **ads=NULL; int num_users; int i; char *qf=(char *)"REPLACE INTO clickhouse_users(username,password,active,max_connections) VALUES('%s','%s',1,%d)"; char *qb=(char *)"REPLACE INTO clickhouse_users(username,password,active,max_connections) VALUES('%s','%s',1,%d)"; char *qfr=(char *)"REPLACE INTO runtime_clickhouse_users(username,password,active,max_connections) VALUES('%s','%s',1,%d)"; char *qbr=(char *)"REPLACE INTO runtime_clickhouse_users(username,password,active,max_connections) VALUES('%s','%s',1,%d)"; char *qfr_stmt1=(char *)"REPLACE INTO runtime_clickhouse_users(username,password,active,max_connections) VALUES(?1,?2,1,?3)"; char *qbr_stmt1=(char *)"REPLACE INTO runtime_clickhouse_users(username,password,active,max_connections) VALUES(?1,?2,1,?3)"; num_users=GloClickHouseAuth->dump_all_users(&ads); if (num_users==0) return; char *q_stmt1_f=NULL; char *q_stmt1_b=NULL; sqlite3_stmt *f_statement1=NULL; sqlite3_stmt *b_statement1=NULL; if (_runtime) { int rc; q_stmt1_f=qfr_stmt1; q_stmt1_b=qbr_stmt1; rc = admindb->prepare_v2(q_stmt1_f, &f_statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(q_stmt1_b, &b_statement1); ASSERT_SQLITE_OK(rc, admindb); } for (i=0; idefault_hostgroup >= 0) { char *q=NULL; if (_runtime==false) { if (ad->__frontend) { q=qf; } else { q=qb; } } else { // _runtime==true if (ad->__frontend) { q=qfr; statement1=f_statement1; } else { q=qbr; statement1=b_statement1; } } if (_runtime==false) { query=(char *)malloc(strlen(q)+strlen(ad->username)*2+strlen(ad->password)+strlen(ad->default_schema)+256); sprintf(query, q, ad->username, ad->password, ad->max_connections); proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); free(query); } else { rc=(*proxy_sqlite3_bind_text)(statement1, 1, ad->username, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 2, ad->password, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, ad->max_connections); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } } free(ad->username); free(ad->password); // this is not initialized with dump_all_users( , false) free(ad->default_schema); // this is not initialized with dump_all_users( , false) free(ad); } if (_runtime) { (*proxy_sqlite3_finalize)(f_statement1); (*proxy_sqlite3_finalize)(b_statement1); } free(ads); } #endif /* PROXYSQLCLICKHOUSE */ void ProxySQL_Admin::save_scheduler_runtime_to_database(bool _runtime) { char *query=NULL; if (_runtime) { query=(char *)"DELETE FROM main.runtime_scheduler"; } else { query=(char *)"DELETE FROM main.scheduler"; } proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); // allocate args only once char **args=(char **)malloc(5*sizeof(char *)); // read lock the scheduler #ifdef PA_PTHREAD_MUTEX pthread_rwlock_rdlock(&scheduler->rwlock); #else spin_rdlock(&scheduler->rwlock); #endif char *q=NULL; if (_runtime) { q=(char *)"INSERT INTO runtime_scheduler VALUES(%lu,%d,%lu,\"%s\" ,%s,%s,%s,%s,%s,'%s')"; } else { q=(char *)"INSERT INTO scheduler VALUES(%lu,%d,%lu,\"%s\" ,%s,%s,%s,%s,%s,'%s')"; } for (std::vector::iterator it = scheduler->Scheduler_Rows.begin() ; it != scheduler->Scheduler_Rows.end(); ++it) { Scheduler_Row *sr=*it; int i; int l=strlen(q); l+=strlen(sr->filename); for (i=0; i<5; i++) { if (sr->args[i]) { args[i]=(char *)malloc(strlen(sr->args[i])+4); sprintf(args[i],"\"%s\"",sr->args[i]); } else { args[i]=(char *)"NULL"; } l+=strlen(args[i]); } char *o=escape_string_single_quotes(sr->comment,false); // issue #643 l+=strlen(o); l+=35; //padding int is_active=0; if (sr->is_active==true) { is_active=1; } char *query=(char *)malloc(l); sprintf(query, q, sr->id, is_active, sr->interval_ms, sr->filename, args[0], args[1], args[2], args[3], args[4], o ); if (o!=sr->comment) { free(o); } for (i=0; i<5; i++) { if (sr->args[i]) { free(args[i]); // free only if we allocated memory } } admindb->execute(query); free(query); } // unlock the scheduler #ifdef PA_PTHREAD_MUTEX pthread_rwlock_unlock(&scheduler->rwlock); #else spin_rdunlock(&scheduler->rwlock); #endif // deallocate args free(args); } void ProxySQL_Admin::save_mysql_servers_runtime_to_database(bool _runtime) { // make sure that the caller has called mysql_servers_wrlock() char *query=NULL; string StrQuery; SQLite3_result *resultset=NULL; // dump mysql_servers if (_runtime) { query=(char *)"DELETE FROM main.runtime_mysql_servers"; } else { query=(char *)"DELETE FROM main.mysql_servers"; } proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); resultset=MyHGM->dump_table_mysql("mysql_servers"); if (resultset) { int rc; sqlite3_stmt *statement1=NULL; sqlite3_stmt *statement32=NULL; char *query1=NULL; char *query32=NULL; std::string query32s = ""; if (_runtime) { query1=(char *)"INSERT INTO runtime_mysql_servers VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)"; query32s = "INSERT INTO runtime_mysql_servers VALUES " + generate_multi_rows_query(32,12); query32 = (char *)query32s.c_str(); } else { query1=(char *)"INSERT INTO mysql_servers VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)"; query32s = "INSERT INTO mysql_servers VALUES " + generate_multi_rows_query(32,12); query32 = (char *)query32s.c_str(); } rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, admindb); int row_idx=0; int max_bulk_row_idx=resultset->rows_count/32; max_bulk_row_idx=max_bulk_row_idx*32; for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r1=*it; int idx=row_idx%32; if (row_idxfields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*12)+2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*12)+3, atoi(r1->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*12)+4, atoi(r1->fields[3])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*12)+5, ( _runtime ? r1->fields[4] : ( strcmp(r1->fields[4],"SHUNNED")==0 ? "ONLINE" : r1->fields[4] ) ), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*12)+6, atoi(r1->fields[5])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*12)+7, atoi(r1->fields[6])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*12)+8, atoi(r1->fields[7])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*12)+9, atoi(r1->fields[8])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*12)+10, atoi(r1->fields[9])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*12)+11, atoi(r1->fields[10])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*12)+12, r1->fields[11], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx==31) { SAFE_SQLITE3_STEP2(statement32); rc=(*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc=(*proxy_sqlite3_bind_int64)(statement1, 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, atoi(r1->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 4, atoi(r1->fields[3])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 5, ( _runtime ? r1->fields[4] : ( strcmp(r1->fields[4],"SHUNNED")==0 ? "ONLINE" : r1->fields[4] ) ), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 6, atoi(r1->fields[5])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 7, atoi(r1->fields[6])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 8, atoi(r1->fields[7])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 9, atoi(r1->fields[8])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 10, atoi(r1->fields[9])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 11, atoi(r1->fields[10])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 12, r1->fields[11], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); } if(resultset) delete resultset; resultset=NULL; // dump mysql_replication_hostgroups if (_runtime) { query=(char *)"DELETE FROM main.runtime_mysql_replication_hostgroups"; } else { query=(char *)"DELETE FROM main.mysql_replication_hostgroups"; } proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); resultset=MyHGM->dump_table_mysql("mysql_replication_hostgroups"); if (resultset) { for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; int l=0; if (r->fields[3]) l=strlen(r->fields[3]); char *q=NULL; if (_runtime) { q=(char *)"INSERT INTO runtime_mysql_replication_hostgroups VALUES(%s,%s,'%s','%s')"; } else { q=(char *)"INSERT INTO mysql_replication_hostgroups VALUES(%s,%s,'%s','%s')"; } char *query=(char *)malloc(strlen(q)+strlen(r->fields[0])+strlen(r->fields[1])+strlen(r->fields[2])+16+l); if (r->fields[3]) { char *o=escape_string_single_quotes(r->fields[3],false); sprintf(query, q, r->fields[0], r->fields[1], r->fields[2], o); if (o!=r->fields[3]) { // there was a copy free(o); } } proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 4, "%s\n", query); admindb->execute(query); free(query); } } if(resultset) delete resultset; resultset=NULL; // dump mysql_group_replication_hostgroups if (_runtime) { query=(char *)"DELETE FROM main.runtime_mysql_group_replication_hostgroups"; } else { query=(char *)"DELETE FROM main.mysql_group_replication_hostgroups"; } proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); resultset=MyHGM->dump_table_mysql("mysql_group_replication_hostgroups"); if (resultset) { int rc; sqlite3_stmt *statement=NULL; char *query=NULL; if (_runtime) { query=(char *)"INSERT INTO runtime_mysql_group_replication_hostgroups(writer_hostgroup,backup_writer_hostgroup,reader_hostgroup,offline_hostgroup,active,max_writers,writer_is_also_reader,max_transactions_behind,comment) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"; } else { query=(char *)"INSERT INTO mysql_group_replication_hostgroups(writer_hostgroup,backup_writer_hostgroup,reader_hostgroup,offline_hostgroup,active,max_writers,writer_is_also_reader,max_transactions_behind,comment) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"; } rc = admindb->prepare_v2(query, &statement); ASSERT_SQLITE_OK(rc, admindb); for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; rc=(*proxy_sqlite3_bind_int64)(statement, 1, atoi(r->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 2, atoi(r->fields[1])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 3, atoi(r->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 4, atoi(r->fields[3])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 5, atoi(r->fields[4])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 6, atoi(r->fields[5])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 7, atoi(r->fields[6])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 8, atoi(r->fields[7])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement, 9, r->fields[8], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement); rc=(*proxy_sqlite3_clear_bindings)(statement); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement); ASSERT_SQLITE_OK(rc, admindb); } (*proxy_sqlite3_finalize)(statement); } if(resultset) delete resultset; resultset = NULL; // dump mysql_galera_hostgroups if (_runtime) { query=(char *)"DELETE FROM main.runtime_mysql_galera_hostgroups"; } else { query=(char *)"DELETE FROM main.mysql_galera_hostgroups"; } proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); resultset=MyHGM->dump_table_mysql("mysql_galera_hostgroups"); if (resultset) { int rc; sqlite3_stmt *statement=NULL; char *query=NULL; if (_runtime) { query=(char *)"INSERT INTO runtime_mysql_galera_hostgroups(writer_hostgroup,backup_writer_hostgroup,reader_hostgroup,offline_hostgroup,active,max_writers,writer_is_also_reader,max_transactions_behind,comment) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"; } else { query=(char *)"INSERT INTO mysql_galera_hostgroups(writer_hostgroup,backup_writer_hostgroup,reader_hostgroup,offline_hostgroup,active,max_writers,writer_is_also_reader,max_transactions_behind,comment) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"; } rc = admindb->prepare_v2(query, &statement); ASSERT_SQLITE_OK(rc, admindb); for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; rc=(*proxy_sqlite3_bind_int64)(statement, 1, atoi(r->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 2, atoi(r->fields[1])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 3, atoi(r->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 4, atoi(r->fields[3])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 5, atoi(r->fields[4])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 6, atoi(r->fields[5])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 7, atoi(r->fields[6])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 8, atoi(r->fields[7])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement, 9, r->fields[8], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement); rc=(*proxy_sqlite3_clear_bindings)(statement); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement); ASSERT_SQLITE_OK(rc, admindb); } (*proxy_sqlite3_finalize)(statement); } if(resultset) delete resultset; resultset = NULL; // dump mysql_aws_aurora_hostgroups if (_runtime) { query=(char *)"DELETE FROM main.runtime_mysql_aws_aurora_hostgroups"; } else { query=(char *)"DELETE FROM main.mysql_aws_aurora_hostgroups"; } proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); resultset=MyHGM->dump_table_mysql("mysql_aws_aurora_hostgroups"); if (resultset) { int rc; sqlite3_stmt *statement=NULL; char *query=NULL; if (_runtime) { query=(char *)"INSERT INTO runtime_mysql_aws_aurora_hostgroups(writer_hostgroup,reader_hostgroup,active,aurora_port,domain_name,max_lag_ms,check_interval_ms,check_timeout_ms,writer_is_also_reader,new_reader_weight,add_lag_ms,min_lag_ms,lag_num_checks,comment) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)"; } else { query=(char *)"INSERT INTO mysql_aws_aurora_hostgroups(writer_hostgroup,reader_hostgroup,active,aurora_port,domain_name,max_lag_ms,check_interval_ms,check_timeout_ms,writer_is_also_reader,new_reader_weight,add_lag_ms,min_lag_ms,lag_num_checks,comment) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)"; } rc = admindb->prepare_v2(query, &statement); ASSERT_SQLITE_OK(rc, admindb); for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; rc=(*proxy_sqlite3_bind_int64)(statement, 1, atoi(r->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 2, atoi(r->fields[1])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 3, atoi(r->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 4, atoi(r->fields[3])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement, 5, r->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 6, atoi(r->fields[5])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 7, atoi(r->fields[6])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 8, atoi(r->fields[7])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 9, atoi(r->fields[8])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 10, atoi(r->fields[9])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 11, atoi(r->fields[10])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 12, atoi(r->fields[11])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement, 13, atoi(r->fields[12])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement, 14, r->fields[13], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement); rc=(*proxy_sqlite3_clear_bindings)(statement); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement); ASSERT_SQLITE_OK(rc, admindb); } (*proxy_sqlite3_finalize)(statement); } if(resultset) delete resultset; resultset=NULL; // dump mysql_hostgroup_attributes StrQuery = "DELETE FROM main."; if (_runtime) StrQuery += "runtime_"; StrQuery += "mysql_hostgroup_attributes"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", StrQuery.c_str()); admindb->execute(StrQuery.c_str()); resultset=MyHGM->dump_table_mysql("mysql_hostgroup_attributes"); if (resultset) { int rc; sqlite3_stmt *statement=NULL; StrQuery = "INSERT INTO "; if (_runtime) StrQuery += "runtime_"; StrQuery += "mysql_hostgroup_attributes (hostgroup_id, max_num_online_servers, autocommit, free_connections_pct, init_connect, multiplex, connection_warming, throttle_connections_per_sec, ignore_session_variables, hostgroup_settings, servers_defaults, comment) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)"; rc = admindb->prepare_v2(StrQuery.c_str(), &statement); ASSERT_SQLITE_OK(rc, admindb); for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; rc=(*proxy_sqlite3_bind_int64)(statement, 1, atol(r->fields[0])); ASSERT_SQLITE_OK(rc, admindb); // hostgroup_id rc=(*proxy_sqlite3_bind_int64)(statement, 2, atol(r->fields[1])); ASSERT_SQLITE_OK(rc, admindb); // max_num_online_servers rc=(*proxy_sqlite3_bind_int64)(statement, 3, atol(r->fields[2])); ASSERT_SQLITE_OK(rc, admindb); // autocommit rc=(*proxy_sqlite3_bind_int64)(statement, 4, atol(r->fields[3])); ASSERT_SQLITE_OK(rc, admindb); // free_connections_pct rc=(*proxy_sqlite3_bind_text)(statement, 5, r->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // variable_name rc=(*proxy_sqlite3_bind_int64)(statement, 6, atol(r->fields[5])); ASSERT_SQLITE_OK(rc, admindb); // multiplex rc=(*proxy_sqlite3_bind_int64)(statement, 7, atol(r->fields[6])); ASSERT_SQLITE_OK(rc, admindb); // connection_warming rc=(*proxy_sqlite3_bind_int64)(statement, 8, atol(r->fields[7])); ASSERT_SQLITE_OK(rc, admindb); // throttle_connections_per_sec rc=(*proxy_sqlite3_bind_text)(statement, 9, r->fields[8], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ignore_session_variables rc=(*proxy_sqlite3_bind_text)(statement, 10, r->fields[9], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // hostgroup_settings rc=(*proxy_sqlite3_bind_text)(statement, 11, r->fields[10], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // servers_defaults rc=(*proxy_sqlite3_bind_text)(statement, 12, r->fields[11], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // comment SAFE_SQLITE3_STEP2(statement); rc=(*proxy_sqlite3_clear_bindings)(statement); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement); ASSERT_SQLITE_OK(rc, admindb); } (*proxy_sqlite3_finalize)(statement); } if(resultset) delete resultset; resultset=NULL; // dump mysql_servers_ssl_params StrQuery = "DELETE FROM main."; if (_runtime) StrQuery += "runtime_"; StrQuery += "mysql_servers_ssl_params"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", StrQuery.c_str()); admindb->execute(StrQuery.c_str()); resultset=MyHGM->dump_table_mysql("mysql_servers_ssl_params"); if (resultset) { int rc; sqlite3_stmt *statement=NULL; StrQuery = "INSERT INTO "; if (_runtime) StrQuery += "runtime_"; StrQuery += "mysql_servers_ssl_params (hostname, port, username, ssl_ca, ssl_cert, ssl_key, ssl_capath, ssl_crl, ssl_crlpath, ssl_cipher, tls_version, comment) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)"; rc = admindb->prepare_v2(StrQuery.c_str(), &statement); ASSERT_SQLITE_OK(rc, admindb); for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; rc=(*proxy_sqlite3_bind_text)(statement, 1, r->fields[0], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // hostname rc=(*proxy_sqlite3_bind_int64)(statement, 2, atol(r->fields[1])); ASSERT_SQLITE_OK(rc, admindb); // port rc=(*proxy_sqlite3_bind_text)(statement, 3, r->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // username rc=(*proxy_sqlite3_bind_text)(statement, 4, r->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_ca rc=(*proxy_sqlite3_bind_text)(statement, 5, r->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_cert rc=(*proxy_sqlite3_bind_text)(statement, 6, r->fields[5], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_key rc=(*proxy_sqlite3_bind_text)(statement, 7, r->fields[6], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_capath rc=(*proxy_sqlite3_bind_text)(statement, 8, r->fields[7], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_crl rc=(*proxy_sqlite3_bind_text)(statement, 9, r->fields[8], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_crlpath rc=(*proxy_sqlite3_bind_text)(statement, 10, r->fields[9], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ssl_cipher rc=(*proxy_sqlite3_bind_text)(statement, 11, r->fields[10], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // tls_version rc=(*proxy_sqlite3_bind_text)(statement, 12, r->fields[11], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // comment SAFE_SQLITE3_STEP2(statement); rc=(*proxy_sqlite3_clear_bindings)(statement); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement); ASSERT_SQLITE_OK(rc, admindb); } (*proxy_sqlite3_finalize)(statement); } if(resultset) delete resultset; resultset=NULL; } void ProxySQL_Admin::save_pgsql_servers_runtime_to_database(bool _runtime) { // make sure that the caller has called pgsql_servers_wrlock() char* query = NULL; string StrQuery; SQLite3_result* resultset = NULL; // dump pgsql_servers if (_runtime) { query = (char*)"DELETE FROM main.runtime_pgsql_servers"; } else { query = (char*)"DELETE FROM main.pgsql_servers"; } proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); resultset = PgHGM->dump_table_pgsql("pgsql_servers"); if (resultset) { int rc; sqlite3_stmt* statement1 = NULL; sqlite3_stmt* statement32 = NULL; //sqlite3 *mydb3=admindb->get_db(); char* query1 = NULL; char* query32 = NULL; std::string query32s = ""; if (_runtime) { query1 = (char*)"INSERT INTO runtime_pgsql_servers VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)"; query32s = "INSERT INTO runtime_pgsql_servers VALUES " + generate_multi_rows_query(32, 11); query32 = (char*)query32s.c_str(); } else { query1 = (char*)"INSERT INTO pgsql_servers VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)"; query32s = "INSERT INTO pgsql_servers VALUES " + generate_multi_rows_query(32, 11); query32 = (char*)query32s.c_str(); } //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query1, -1, &statement1, 0); rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query32, -1, &statement32, 0); rc = admindb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, admindb); int row_idx = 0; int max_bulk_row_idx = resultset->rows_count / 32; max_bulk_row_idx = max_bulk_row_idx * 32; for (std::vector::iterator it = resultset->rows.begin(); it != resultset->rows.end(); ++it) { SQLite3_row* r1 = *it; int idx = row_idx % 32; if (row_idx < max_bulk_row_idx) { // bulk rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 11) + 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 11) + 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 11) + 3, atoi(r1->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 11) + 4, (_runtime ? r1->fields[3] : (strcmp(r1->fields[4], "SHUNNED") == 0 ? "ONLINE" : r1->fields[3])), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 11) + 5, atoi(r1->fields[4])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 11) + 6, atoi(r1->fields[5])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 11) + 7, atoi(r1->fields[6])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 11) + 8, atoi(r1->fields[7])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 11) + 9, atoi(r1->fields[8])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 11) + 10, atoi(r1->fields[9])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 11) + 11, r1->fields[10], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx == 31) { SAFE_SQLITE3_STEP2(statement32); rc = (*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc = (*proxy_sqlite3_bind_int64)(statement1, 1, atoi(r1->fields[0])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 3, atoi(r1->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 4, (_runtime ? r1->fields[3] : (strcmp(r1->fields[3], "SHUNNED") == 0 ? "ONLINE" : r1->fields[3])), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 5, atoi(r1->fields[4])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 6, atoi(r1->fields[5])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 7, atoi(r1->fields[6])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 8, atoi(r1->fields[7])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 9, atoi(r1->fields[8])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_int64)(statement1, 10, atoi(r1->fields[9])); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_bind_text)(statement1, 11, r1->fields[10], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); } if (resultset) delete resultset; resultset = NULL; // dump pgsql_replication_hostgroups if (_runtime) { query = (char*)"DELETE FROM main.runtime_pgsql_replication_hostgroups"; } else { query = (char*)"DELETE FROM main.pgsql_replication_hostgroups"; } proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); resultset = PgHGM->dump_table_pgsql("pgsql_replication_hostgroups"); if (resultset) { for (std::vector::iterator it = resultset->rows.begin(); it != resultset->rows.end(); ++it) { SQLite3_row* r = *it; int l = 0; if (r->fields[3]) l = strlen(r->fields[3]); char* q = NULL; if (_runtime) { q = (char*)"INSERT INTO runtime_pgsql_replication_hostgroups VALUES(%s,%s,'%s','%s')"; } else { q = (char*)"INSERT INTO pgsql_replication_hostgroups VALUES(%s,%s,'%s','%s')"; } char* query = (char*)malloc(strlen(q) + strlen(r->fields[0]) + strlen(r->fields[1]) + strlen(r->fields[2]) + 16 + l); if (r->fields[3]) { char* o = escape_string_single_quotes(r->fields[3], false); sprintf(query, q, r->fields[0], r->fields[1], r->fields[2], o); if (o != r->fields[3]) { // there was a copy free(o); } //} else { //sprintf(query, q, r->fields[0], r->fields[1], r->fields[2], r->fields[3]); } proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 4, "%s\n", query); admindb->execute(query); free(query); } } if (resultset) delete resultset; resultset = NULL; // dump pgsql_hostgroup_attributes StrQuery = "DELETE FROM main."; if (_runtime) StrQuery += "runtime_"; StrQuery += "pgsql_hostgroup_attributes"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", StrQuery.c_str()); admindb->execute(StrQuery.c_str()); resultset = PgHGM->dump_table_pgsql("pgsql_hostgroup_attributes"); if (resultset) { int rc; sqlite3_stmt* statement = NULL; StrQuery = "INSERT INTO "; if (_runtime) StrQuery += "runtime_"; StrQuery += "pgsql_hostgroup_attributes (hostgroup_id, max_num_online_servers, autocommit, free_connections_pct, init_connect, multiplex, connection_warming, throttle_connections_per_sec, ignore_session_variables, hostgroup_settings, servers_defaults, comment) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)"; rc = admindb->prepare_v2(StrQuery.c_str(), &statement); ASSERT_SQLITE_OK(rc, admindb); //proxy_info("New pgsql_aws_aurora_hostgroups table\n"); for (std::vector::iterator it = resultset->rows.begin(); it != resultset->rows.end(); ++it) { SQLite3_row* r = *it; rc = (*proxy_sqlite3_bind_int64)(statement, 1, atol(r->fields[0])); ASSERT_SQLITE_OK(rc, admindb); // hostgroup_id rc = (*proxy_sqlite3_bind_int64)(statement, 2, atol(r->fields[1])); ASSERT_SQLITE_OK(rc, admindb); // max_num_online_servers rc = (*proxy_sqlite3_bind_int64)(statement, 3, atol(r->fields[2])); ASSERT_SQLITE_OK(rc, admindb); // autocommit rc = (*proxy_sqlite3_bind_int64)(statement, 4, atol(r->fields[3])); ASSERT_SQLITE_OK(rc, admindb); // free_connections_pct rc = (*proxy_sqlite3_bind_text)(statement, 5, r->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // variable_name rc = (*proxy_sqlite3_bind_int64)(statement, 6, atol(r->fields[5])); ASSERT_SQLITE_OK(rc, admindb); // multiplex rc = (*proxy_sqlite3_bind_int64)(statement, 7, atol(r->fields[6])); ASSERT_SQLITE_OK(rc, admindb); // connection_warming rc = (*proxy_sqlite3_bind_int64)(statement, 8, atol(r->fields[7])); ASSERT_SQLITE_OK(rc, admindb); // throttle_connections_per_sec rc = (*proxy_sqlite3_bind_text)(statement, 9, r->fields[8], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // ignore_session_variables rc = (*proxy_sqlite3_bind_text)(statement, 10, r->fields[9], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // hostgroup_settings rc = (*proxy_sqlite3_bind_text)(statement, 11, r->fields[10], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // servers_defaults rc = (*proxy_sqlite3_bind_text)(statement, 12, r->fields[11], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); // comment SAFE_SQLITE3_STEP2(statement); rc = (*proxy_sqlite3_clear_bindings)(statement); ASSERT_SQLITE_OK(rc, admindb); rc = (*proxy_sqlite3_reset)(statement); ASSERT_SQLITE_OK(rc, admindb); } (*proxy_sqlite3_finalize)(statement); } if (resultset) delete resultset; resultset = NULL; } void ProxySQL_Admin::load_scheduler_to_runtime() { char *error=NULL; int cols=0; int affected_rows=0; SQLite3_result *resultset=NULL; char *query=(char *)"SELECT * FROM scheduler"; admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { scheduler->update_table(resultset); } if (resultset) delete resultset; resultset=NULL; } void ProxySQL_Admin::load_mysql_servers_to_runtime(const incoming_servers_t& incoming_servers, const runtime_mysql_servers_checksum_t& peer_runtime_mysql_server, const mysql_servers_v2_checksum_t& peer_mysql_server_v2) { // make sure that the caller has called mysql_servers_wrlock() char *error=NULL; int cols=0; int affected_rows=0; SQLite3_result *resultset=NULL; SQLite3_result *resultset_servers=NULL; SQLite3_result *resultset_replication=NULL; SQLite3_result *resultset_group_replication=NULL; SQLite3_result *resultset_galera=NULL; SQLite3_result *resultset_aws_aurora=NULL; SQLite3_result *resultset_hostgroup_attributes=NULL; SQLite3_result *resultset_mysql_servers_ssl_params=NULL; SQLite3_result* runtime_mysql_servers = incoming_servers.runtime_mysql_servers; SQLite3_result* incoming_replication_hostgroups = incoming_servers.incoming_replication_hostgroups; SQLite3_result* incoming_group_replication_hostgroups = incoming_servers.incoming_group_replication_hostgroups; SQLite3_result* incoming_galera_hostgroups = incoming_servers.incoming_galera_hostgroups; SQLite3_result* incoming_aurora_hostgroups = incoming_servers.incoming_aurora_hostgroups; SQLite3_result* incoming_hostgroup_attributes = incoming_servers.incoming_hostgroup_attributes; SQLite3_result* incoming_mysql_servers_ssl_params = incoming_servers.incoming_mysql_servers_ssl_params; SQLite3_result* incoming_mysql_servers_v2 = incoming_servers.incoming_mysql_servers_v2; const char *query=(char *)"SELECT hostgroup_id,hostname,port,gtid_port,status,weight,compression,max_connections,max_replication_lag,use_ssl,max_latency_ms,comment FROM main.mysql_servers ORDER BY hostgroup_id, hostname, port"; if (runtime_mysql_servers == nullptr) { proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute_statement(query, &error, &cols, &affected_rows, &resultset_servers); } else { resultset_servers = runtime_mysql_servers; } //MyHGH->wrlock(); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { MyHGM->servers_add(resultset_servers); } // memory leak was detected here. The following few lines fix that if (runtime_mysql_servers == nullptr) { if (resultset_servers != nullptr) { delete resultset_servers; resultset_servers = nullptr; } } resultset=NULL; query=(char *)"SELECT a.* FROM mysql_replication_hostgroups a JOIN mysql_replication_hostgroups b ON a.writer_hostgroup=b.reader_hostgroup WHERE b.reader_hostgroup"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; proxy_error("Incompatible entry in mysql_replication_hostgroups will be ignored : ( %s , %s )\n", r->fields[0], r->fields[1]); } } if (resultset) delete resultset; resultset=NULL; query=(char *)"SELECT a.* FROM mysql_replication_hostgroups a LEFT JOIN mysql_replication_hostgroups b ON a.writer_hostgroup=b.reader_hostgroup WHERE b.reader_hostgroup IS NULL ORDER BY writer_hostgroup"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); if (incoming_replication_hostgroups == nullptr) { admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset_replication); } else { resultset_replication = incoming_replication_hostgroups; } //MyHGH->wrlock(); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { // Pass the resultset to MyHGM MyHGM->save_incoming_mysql_table(resultset_replication,"mysql_replication_hostgroups"); } //if (resultset) delete resultset; //resultset=NULL; // support for Group Replication, table mysql_group_replication_hostgroups // look for invalid combinations query=(char *)"SELECT a.* FROM mysql_group_replication_hostgroups a JOIN mysql_group_replication_hostgroups b ON a.writer_hostgroup=b.reader_hostgroup WHERE b.reader_hostgroup UNION ALL SELECT a.* FROM mysql_group_replication_hostgroups a JOIN mysql_group_replication_hostgroups b ON a.writer_hostgroup=b.backup_writer_hostgroup WHERE b.backup_writer_hostgroup UNION ALL SELECT a.* FROM mysql_group_replication_hostgroups a JOIN mysql_group_replication_hostgroups b ON a.writer_hostgroup=b.offline_hostgroup WHERE b.offline_hostgroup"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; proxy_error("Incompatible entry in mysql_group_replication_hostgroups will be ignored : ( %s , %s , %s , %s )\n", r->fields[0], r->fields[1], r->fields[2], r->fields[3]); } } if (resultset) delete resultset; resultset=NULL; query=(char *)"SELECT a.* FROM mysql_group_replication_hostgroups a LEFT JOIN mysql_group_replication_hostgroups b ON (a.writer_hostgroup=b.reader_hostgroup OR a.writer_hostgroup=b.backup_writer_hostgroup OR a.writer_hostgroup=b.offline_hostgroup) WHERE b.reader_hostgroup IS NULL AND b.backup_writer_hostgroup IS NULL AND b.offline_hostgroup IS NULL ORDER BY writer_hostgroup"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); if (incoming_group_replication_hostgroups == nullptr) { admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset_group_replication); } else { resultset_group_replication = incoming_group_replication_hostgroups; } if (error) { proxy_error("Error on %s : %s\n", query, error); } else { // Pass the resultset to MyHGM MyHGM->save_incoming_mysql_table(resultset_group_replication,"mysql_group_replication_hostgroups"); } // support for Galera, table mysql_galera_hostgroups // look for invalid combinations query=(char *)"SELECT a.* FROM mysql_galera_hostgroups a JOIN mysql_galera_hostgroups b ON a.writer_hostgroup=b.reader_hostgroup WHERE b.reader_hostgroup UNION ALL SELECT a.* FROM mysql_galera_hostgroups a JOIN mysql_galera_hostgroups b ON a.writer_hostgroup=b.backup_writer_hostgroup WHERE b.backup_writer_hostgroup UNION ALL SELECT a.* FROM mysql_galera_hostgroups a JOIN mysql_galera_hostgroups b ON a.writer_hostgroup=b.offline_hostgroup WHERE b.offline_hostgroup"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; proxy_error("Incompatible entry in mysql_galera_hostgroups will be ignored : ( %s , %s , %s , %s )\n", r->fields[0], r->fields[1], r->fields[2], r->fields[3]); } } if (resultset) delete resultset; resultset=NULL; query=(char *)"SELECT a.* FROM mysql_galera_hostgroups a LEFT JOIN mysql_galera_hostgroups b ON (a.writer_hostgroup=b.reader_hostgroup OR a.writer_hostgroup=b.backup_writer_hostgroup OR a.writer_hostgroup=b.offline_hostgroup) WHERE b.reader_hostgroup IS NULL AND b.backup_writer_hostgroup IS NULL AND b.offline_hostgroup IS NULL ORDER BY writer_hostgroup"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); if (incoming_galera_hostgroups == nullptr) { admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset_galera); } else { resultset_galera = incoming_galera_hostgroups; } if (error) { proxy_error("Error on %s : %s\n", query, error); } else { // Pass the resultset to MyHGM MyHGM->save_incoming_mysql_table(resultset_galera, "mysql_galera_hostgroups"); } // support for AWS Aurora, table mysql_aws_aurora_hostgroups // look for invalid combinations query=(char *)"SELECT a.* FROM mysql_aws_aurora_hostgroups a JOIN mysql_aws_aurora_hostgroups b ON a.writer_hostgroup=b.reader_hostgroup WHERE b.reader_hostgroup"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; proxy_error("Incompatible entry in mysql_aws_aurora_hostgroups will be ignored : ( %s , %s , %s , %s )\n", r->fields[0], r->fields[1], r->fields[2], r->fields[3]); } } if (resultset) delete resultset; resultset=NULL; //#ifdef TEST_AURORA // temporary enabled only for testing purpose query=(char *)"SELECT a.* FROM mysql_aws_aurora_hostgroups a LEFT JOIN mysql_aws_aurora_hostgroups b ON (a.writer_hostgroup=b.reader_hostgroup) WHERE b.reader_hostgroup IS NULL ORDER BY writer_hostgroup"; //#else // query=(char *)"SELECT a.* FROM mysql_aws_aurora_hostgroups a WHERE 1=0"; //#endif proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); if (incoming_aurora_hostgroups == nullptr) { admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset_aws_aurora); } else { resultset_aws_aurora = incoming_aurora_hostgroups; } if (error) { proxy_error("Error on %s : %s\n", query, error); } else { // Pass the resultset to MyHGM MyHGM->save_incoming_mysql_table(resultset_aws_aurora,"mysql_aws_aurora_hostgroups"); } // support for hostgroup attributes, table mysql_hostgroup_attributes query = (char *)"SELECT * FROM mysql_hostgroup_attributes ORDER BY hostgroup_id"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); if (incoming_hostgroup_attributes == nullptr) { admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset_hostgroup_attributes); } else { resultset_hostgroup_attributes = incoming_hostgroup_attributes; } if (error) { proxy_error("Error on %s : %s\n", query, error); } else { // Pass the resultset to MyHGM MyHGM->save_incoming_mysql_table(resultset_hostgroup_attributes, "mysql_hostgroup_attributes"); } // support for SSL parameters, table mysql_servers_ssl_params query = (char *)"SELECT * FROM mysql_servers_ssl_params ORDER BY hostname, port, username"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); if (incoming_mysql_servers_ssl_params == nullptr) { admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset_mysql_servers_ssl_params); } else { resultset_mysql_servers_ssl_params = incoming_mysql_servers_ssl_params; } if (error) { proxy_error("Error on %s : %s\n", query, error); } else { // Pass the resultset to MyHGM MyHGM->save_incoming_mysql_table(resultset_mysql_servers_ssl_params, "mysql_servers_ssl_params"); } // commit all the changes MyHGM->commit( { runtime_mysql_servers, peer_runtime_mysql_server }, { incoming_mysql_servers_v2, peer_mysql_server_v2 }, false, true ); // quering runtime table will update and return latest records, so this is not needed. // GloAdmin->save_mysql_servers_runtime_to_database(true); // clean up if (resultset) delete resultset; resultset=NULL; if (resultset_replication) { delete resultset_replication; resultset_replication=NULL; } if (resultset_group_replication) { //delete resultset_replication; // do not delete, resultset is stored in MyHGM resultset_group_replication=NULL; } if (resultset_galera) { //delete resultset_galera; // do not delete, resultset is stored in MyHGM resultset_galera=NULL; } if (resultset_aws_aurora) { //delete resultset_aws_aurora; // do not delete, resultset is stored in MyHGM resultset_aws_aurora=NULL; } if (resultset_hostgroup_attributes) { resultset_hostgroup_attributes = NULL; } if (resultset_mysql_servers_ssl_params) { resultset_mysql_servers_ssl_params = NULL; } } void ProxySQL_Admin::load_pgsql_servers_to_runtime(const incoming_pgsql_servers_t& incoming_pgsql_servers, const runtime_pgsql_servers_checksum_t& peer_runtime_pgsql_server, const pgsql_servers_v2_checksum_t& peer_pgsql_server_v2) { // make sure that the caller has called pgsql_servers_wrlock() char* error = NULL; int cols = 0; int affected_rows = 0; SQLite3_result* resultset = NULL; SQLite3_result* resultset_servers = NULL; SQLite3_result* resultset_replication = NULL; SQLite3_result* resultset_hostgroup_attributes = NULL; SQLite3_result* runtime_pgsql_servers = incoming_pgsql_servers.runtime_pgsql_servers; SQLite3_result* incoming_replication_hostgroups = incoming_pgsql_servers.incoming_replication_hostgroups; SQLite3_result* incoming_hostgroup_attributes = incoming_pgsql_servers.incoming_hostgroup_attributes; SQLite3_result* incoming_pgsql_servers_v2 = incoming_pgsql_servers.incoming_pgsql_servers_v2; const char* query = (char*)"SELECT hostgroup_id,hostname,port,status,weight,compression,max_connections,max_replication_lag,use_ssl,max_latency_ms,comment FROM main.pgsql_servers ORDER BY hostgroup_id, hostname, port"; if (runtime_pgsql_servers == nullptr) { proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute_statement(query, &error, &cols, &affected_rows, &resultset_servers); } else { resultset_servers = runtime_pgsql_servers; } //MyHGH->wrlock(); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { PgHGM->servers_add(resultset_servers); } // memory leak was detected here. The following few lines fix that if (runtime_pgsql_servers == nullptr) { if (resultset_servers != nullptr) { delete resultset_servers; resultset_servers = nullptr; } } resultset = NULL; query = (char*)"SELECT a.* FROM pgsql_replication_hostgroups a JOIN pgsql_replication_hostgroups b ON a.writer_hostgroup=b.reader_hostgroup WHERE b.reader_hostgroup"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute_statement(query, &error, &cols, &affected_rows, &resultset); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { for (std::vector::iterator it = resultset->rows.begin(); it != resultset->rows.end(); ++it) { SQLite3_row* r = *it; proxy_error("Incompatible entry in pgsql_replication_hostgroups will be ignored : ( %s , %s )\n", r->fields[0], r->fields[1]); } } if (resultset) delete resultset; resultset = NULL; query = (char*)"SELECT a.* FROM pgsql_replication_hostgroups a LEFT JOIN pgsql_replication_hostgroups b ON a.writer_hostgroup=b.reader_hostgroup WHERE b.reader_hostgroup IS NULL ORDER BY writer_hostgroup"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); if (incoming_replication_hostgroups == nullptr) { admindb->execute_statement(query, &error, &cols, &affected_rows, &resultset_replication); } else { resultset_replication = incoming_replication_hostgroups; } if (error) { proxy_error("Error on %s : %s\n", query, error); } else { // Pass the resultset to PgHGM PgHGM->save_incoming_pgsql_table(resultset_replication, "pgsql_replication_hostgroups"); } //if (resultset) delete resultset; //resultset=NULL; // support for hostgroup attributes, table pgsql_hostgroup_attributes query = (char*)"SELECT * FROM pgsql_hostgroup_attributes ORDER BY hostgroup_id"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); if (incoming_hostgroup_attributes == nullptr) { admindb->execute_statement(query, &error, &cols, &affected_rows, &resultset_hostgroup_attributes); } else { resultset_hostgroup_attributes = incoming_hostgroup_attributes; } if (error) { proxy_error("Error on %s : %s\n", query, error); } else { // Pass the resultset to PgHGM PgHGM->save_incoming_pgsql_table(resultset_hostgroup_attributes, "pgsql_hostgroup_attributes"); } // commit all the changes PgHGM->commit( { runtime_pgsql_servers, peer_runtime_pgsql_server }, { incoming_pgsql_servers_v2, peer_pgsql_server_v2 }, false, true ); // quering runtime table will update and return latest records, so this is not needed. // GloAdmin->save_pgsql_servers_runtime_to_database(true); // clean up if (resultset) delete resultset; resultset = NULL; if (resultset_replication) { delete resultset_replication; resultset_replication = NULL; } if (resultset_hostgroup_attributes) { resultset_hostgroup_attributes = NULL; } } char * ProxySQL_Admin::load_mysql_firewall_to_runtime() { // NOTE: firewall is currently NOT part of Cluster unsigned long long curtime1=monotonic_time(); char *error_users=NULL; int cols_users=0; int affected_rows_users=0; char *error_rules=NULL; int cols_rules=0; int affected_rows_rules=0; char *error_sqli_fingerprints=NULL; int cols_sqli_fingerprints=0; int affected_rows_sqli_fingerprints=0; bool success = false; if (GloMyQPro==NULL) return (char *)"Global Query Processor not started: command impossible to run"; char *query_users = (char *)"SELECT * FROM mysql_firewall_whitelist_users"; char *query_rules = (char *)"SELECT * FROM mysql_firewall_whitelist_rules"; char *query_sqli_fingerprints = (char *)"SELECT * FROM mysql_firewall_whitelist_sqli_fingerprints"; SQLite3_result *resultset_users = NULL; SQLite3_result *resultset_rules = NULL; SQLite3_result *resultset_sqli_fingerprints = NULL; admindb->execute_statement(query_users, &error_users , &cols_users , &affected_rows_users , &resultset_users); admindb->execute_statement(query_rules, &error_rules , &cols_rules , &affected_rows_rules , &resultset_rules); admindb->execute_statement(query_sqli_fingerprints, &error_sqli_fingerprints , &cols_sqli_fingerprints , &affected_rows_sqli_fingerprints , &resultset_sqli_fingerprints); if (error_users) { proxy_error("Error on %s : %s\n", query_users, error_users); } else if (error_rules) { proxy_error("Error on %s : %s\n", query_rules, error_rules); } else if (error_sqli_fingerprints) { proxy_error("Error on %s : %s\n", query_sqli_fingerprints, error_sqli_fingerprints); } else { success = true; GloMyQPro->load_firewall(resultset_users, resultset_rules, resultset_sqli_fingerprints); } if (success == false) { // clean up if (resultset_users) { free(resultset_users); } if (resultset_rules) { free(resultset_rules); } if (resultset_sqli_fingerprints) { free(resultset_sqli_fingerprints); } } unsigned long long curtime2=monotonic_time(); curtime1 = curtime1/1000; curtime2 = curtime2/1000; if (curtime2-curtime1 > 1000) { proxy_info("locked for %llums\n", curtime2-curtime1); } return NULL; } char* ProxySQL_Admin::load_pgsql_firewall_to_runtime() { // NOTE: firewall is currently NOT part of Cluster unsigned long long curtime1 = monotonic_time(); char* error_users = NULL; int cols_users = 0; int affected_rows_users = 0; char* error_rules = NULL; int cols_rules = 0; int affected_rows_rules = 0; char* error_sqli_fingerprints = NULL; int cols_sqli_fingerprints = 0; int affected_rows_sqli_fingerprints = 0; bool success = false; if (GloPgQPro == NULL) return (char*)"Global Query Processor not started: command impossible to run"; char* query_users = (char*)"SELECT * FROM pgsql_firewall_whitelist_users"; char* query_rules = (char*)"SELECT * FROM pgsql_firewall_whitelist_rules"; char* query_sqli_fingerprints = (char*)"SELECT * FROM pgsql_firewall_whitelist_sqli_fingerprints"; SQLite3_result* resultset_users = NULL; SQLite3_result* resultset_rules = NULL; SQLite3_result* resultset_sqli_fingerprints = NULL; admindb->execute_statement(query_users, &error_users, &cols_users, &affected_rows_users, &resultset_users); admindb->execute_statement(query_rules, &error_rules, &cols_rules, &affected_rows_rules, &resultset_rules); admindb->execute_statement(query_sqli_fingerprints, &error_sqli_fingerprints, &cols_sqli_fingerprints, &affected_rows_sqli_fingerprints, &resultset_sqli_fingerprints); if (error_users) { proxy_error("Error on %s : %s\n", query_users, error_users); } else if (error_rules) { proxy_error("Error on %s : %s\n", query_rules, error_rules); } else if (error_sqli_fingerprints) { proxy_error("Error on %s : %s\n", query_sqli_fingerprints, error_sqli_fingerprints); } else { success = true; GloPgQPro->load_firewall(resultset_users, resultset_rules, resultset_sqli_fingerprints); } if (success == false) { // clean up if (resultset_users) { free(resultset_users); } if (resultset_rules) { free(resultset_rules); } if (resultset_sqli_fingerprints) { free(resultset_sqli_fingerprints); } } unsigned long long curtime2 = monotonic_time(); curtime1 = curtime1 / 1000; curtime2 = curtime2 / 1000; if (curtime2 - curtime1 > 1000) { proxy_info("locked for %llums\n", curtime2 - curtime1); } return NULL; } char* ProxySQL_Admin::load_mysql_query_rules_to_runtime(SQLite3_result* SQLite3_query_rules_resultset, SQLite3_result* SQLite3_query_rules_fast_routing_resultset, const std::string& checksum, const time_t epoch) { // About the queries used here, see notes about CLUSTER_QUERY_MYSQL_QUERY_RULES and // CLUSTER_QUERY_MYSQL_QUERY_RULES_FAST_ROUTING in ProxySQL_Cluster.hpp char *error=NULL; int cols=0; int affected_rows=0; if (GloMyQPro==NULL) return (char *)"Global Query Processor not started: command impossible to run"; SQLite3_result *resultset=NULL; char *query=(char *)"SELECT rule_id, username, schemaname, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, gtid_from_hostgroup, log, apply, attributes, comment FROM main.mysql_query_rules WHERE active=1 ORDER BY rule_id"; if (SQLite3_query_rules_resultset==NULL) { admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); } else { // Cluster can pass SQLite3_query_rules_resultset , to absolutely speed up // the process and therefore there is no need to run any query resultset = SQLite3_query_rules_resultset; } char *error2 = NULL; int cols2 = 0; int affected_rows2 = 0; SQLite3_result *resultset2 = NULL; char *query2=(char *)"SELECT username, schemaname, flagIN, destination_hostgroup, comment FROM main.mysql_query_rules_fast_routing ORDER BY username, schemaname, flagIN"; if (SQLite3_query_rules_fast_routing_resultset==NULL) { admindb->execute_statement(query2, &error2 , &cols2 , &affected_rows2 , &resultset2); } else { // Cluster can pass SQLite3_query_rules_fast_routing_resultset , to absolutely speed up // the process and therefore there is no need to run any query resultset2 = SQLite3_query_rules_fast_routing_resultset; } if (error) { proxy_error("Error on %s : %s\n", query, error); } else if (error2) { proxy_error("Error on %s : %s\n", query2, error2); } else { fast_routing_hashmap_t fast_routing_hashmap(GloMyQPro->create_fast_routing_hashmap(resultset2) ); #ifdef BENCHMARK_FASTROUTING_LOAD for (int i=0; i<10; i++) { #endif // BENCHMARK_FASTROUTING_LOAD // Computed resultsets checksums outside of critical sections uint64_t hash1 = 0; uint64_t hash2 = 0; if ( SQLite3_query_rules_resultset == nullptr || SQLite3_query_rules_fast_routing_resultset == nullptr ) { hash1 = resultset->raw_checksum(); hash2 = resultset2->raw_checksum(); } unsigned long long curtime1 = monotonic_time(); GloMyQPro->wrlock(); // Checksums are always generated - 'admin-checksum_*' deprecated { pthread_mutex_lock(&GloVars.checksum_mutex); char* buff = nullptr; char buf[20]; // If both the resultsets are supplied, then the supplied checksum is the already computed one. if ( SQLite3_query_rules_resultset == nullptr || SQLite3_query_rules_fast_routing_resultset == nullptr ) { hash1 += hash2; uint32_t d32[2]; memcpy(&d32, &hash1, sizeof(hash1)); sprintf(buf,"0x%0X%0X", d32[0], d32[1]); buff = buf; } else { buff = const_cast(checksum.c_str()); } GloVars.checksums_values.mysql_query_rules.set_checksum(buff); GloVars.checksums_values.mysql_query_rules.version++; time_t t = time(NULL); // Since the supplied checksum is the already computed one and both resultset are // supplied there is no need for comparsion, because we will be comparing it with itself. bool same_checksum = SQLite3_query_rules_resultset != nullptr && SQLite3_query_rules_fast_routing_resultset != nullptr; bool matching_checksums = same_checksum || (GloVars.checksums_values.mysql_query_rules.checksum == checksum); if (epoch != 0 && checksum != "" && matching_checksums) { GloVars.checksums_values.mysql_query_rules.epoch = epoch; } else { GloVars.checksums_values.mysql_query_rules.epoch = t; } GloVars.epoch_version = t; GloVars.generate_global_checksum(); GloVars.checksums_values.updates_cnt++; pthread_mutex_unlock(&GloVars.checksum_mutex); proxy_info( "Computed checksum for 'LOAD MYSQL QUERY RULES TO RUNTIME' was '%s', with epoch '%llu'\n", GloVars.checksums_values.mysql_query_rules.checksum, GloVars.checksums_values.mysql_query_rules.epoch ); } rules_mem_sts_t prev_rules_data(GloMyQPro->reset_all(false) ); QP_rule_t * nqpr; for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; if (r->fields[4]) { char *pct = NULL; if (strlen(r->fields[4]) >= INET6_ADDRSTRLEN) { proxy_error("Query rule with rule_id=%s has an invalid client_addr: %s\n", r->fields[0], r->fields[4]); continue; } pct = strchr(r->fields[4],'%'); if (pct) { // there is a wildcard if (strlen(pct) == 1) { // % is at the end of the string, good } else { proxy_error("Query rule with rule_id=%s has a wildcard that is not at the end of client_addr: %s\n", r->fields[0], r->fields[4]); continue; } } } nqpr=GloMyQPro->new_query_rule( atoi(r->fields[0]), // rule_id true, r->fields[1], // username r->fields[2], // schemaname atoi(r->fields[3]), // flagIN r->fields[4], // client_addr r->fields[5], // proxy_addr (r->fields[6]==NULL ? -1 : atol(r->fields[6])), // proxy_port r->fields[7], // digest r->fields[8], // match_digest r->fields[9], // match_pattern (atoi(r->fields[10])==1 ? true : false), // negate_match_pattern r->fields[11], // re_modifiers (r->fields[12]==NULL ? -1 : atol(r->fields[12])), // flagOUT r->fields[13], // replae_pattern (r->fields[14]==NULL ? -1 : atoi(r->fields[14])), // destination_hostgroup (r->fields[15]==NULL ? -1 : atol(r->fields[15])), // cache_ttl (r->fields[16]==NULL ? -1 : atol(r->fields[16])), // cache_empty_result (r->fields[17]==NULL ? -1 : atol(r->fields[17])), // cache_timeout (r->fields[18]==NULL ? -1 : atol(r->fields[18])), // reconnect (r->fields[19]==NULL ? -1 : atol(r->fields[19])), // timeout (r->fields[20]==NULL ? -1 : atol(r->fields[20])), // retries (r->fields[21]==NULL ? -1 : atol(r->fields[21])), // delay (r->fields[22]==NULL ? -1 : atol(r->fields[22])), // next_query_flagIN (r->fields[23]==NULL ? -1 : atol(r->fields[23])), // mirror_flagOUT (r->fields[24]==NULL ? -1 : atol(r->fields[24])), // mirror_hostgroup r->fields[25], // error_msg r->fields[26], // OK_msg (r->fields[27]==NULL ? -1 : atol(r->fields[27])), // sticky_conn (r->fields[28]==NULL ? -1 : atol(r->fields[28])), // multiplex (r->fields[29]==NULL ? -1 : atol(r->fields[29])), // gtid_from_hostgroup (r->fields[30]==NULL ? -1 : atol(r->fields[30])), // log (atoi(r->fields[31])==1 ? true : false), r->fields[32], // attributes r->fields[33] // comment ); GloMyQPro->insert(nqpr, false); } GloMyQPro->sort(false); #ifdef BENCHMARK_FASTROUTING_LOAD // load a copy of resultset and resultset2 SQLite3_result *resultset3 = new SQLite3_result(resultset); GloMyQPro->save_query_rules(resultset3); SQLite3_result *resultset4 = new SQLite3_result(resultset2); GloMyQPro->load_fast_routing(resultset4); #else // load the original resultset and resultset2 GloMyQPro->save_query_rules(resultset); SQLite3_result* prev_fast_routing_resultset=GloMyQPro->load_fast_routing(fast_routing_hashmap); #endif // BENCHMARK_FASTROUTING_LOAD GloMyQPro->commit(); #ifdef BENCHMARK_FASTROUTING_LOAD } #endif // BENCHMARK_FASTROUTING_LOAD GloMyQPro->wrunlock(); unsigned long long curtime2 = monotonic_time(); unsigned long long elapsed_ms = (curtime2/1000) - (curtime1/1000); if (elapsed_ms > 5) { proxy_info("Query processor locked for %llums\n", curtime2 - curtime1); } // Free previous 'fast_routing' structures outside of critical section { delete prev_fast_routing_resultset; if (prev_rules_data.rules_fast_routing) { kh_destroy(khStrInt, prev_rules_data.rules_fast_routing); } if (prev_rules_data.rules_fast_routing___keys_values) { free(prev_rules_data.rules_fast_routing___keys_values); } __reset_rules(&prev_rules_data.query_rules); } } // if (resultset) delete resultset; // never delete it. GloMyQPro saves it // if (resultset2) delete resultset2; // never delete it. GloMyQPro saves it return NULL; } char* ProxySQL_Admin::load_pgsql_query_rules_to_runtime(SQLite3_result* SQLite3_query_rules_resultset, SQLite3_result* SQLite3_query_rules_fast_routing_resultset, const std::string& checksum, const time_t epoch) { // About the queries used here, see notes about CLUSTER_QUERY_PGSQL_QUERY_RULES and // CLUSTER_QUERY_PGSQL_QUERY_RULES_FAST_ROUTING in ProxySQL_Cluster.hpp char* error = NULL; int cols = 0; int affected_rows = 0; if (GloPgQPro == NULL) return (char*)"Global Query Processor not started: command impossible to run"; SQLite3_result* resultset = NULL; char* query = (char*)"SELECT rule_id, username, database, flagIN, client_addr, proxy_addr, proxy_port, digest, match_digest, match_pattern, negate_match_pattern, re_modifiers, flagOUT, replace_pattern, destination_hostgroup, cache_ttl, cache_empty_result, cache_timeout, reconnect, timeout, retries, delay, next_query_flagIN, mirror_flagOUT, mirror_hostgroup, error_msg, ok_msg, sticky_conn, multiplex, log, apply, attributes, comment FROM main.pgsql_query_rules WHERE active=1 ORDER BY rule_id"; if (SQLite3_query_rules_resultset == NULL) { admindb->execute_statement(query, &error, &cols, &affected_rows, &resultset); } else { // Cluster can pass SQLite3_query_rules_resultset , to absolutely speed up // the process and therefore there is no need to run any query resultset = SQLite3_query_rules_resultset; } char* error2 = NULL; int cols2 = 0; int affected_rows2 = 0; SQLite3_result* resultset2 = NULL; char* query2 = (char*)"SELECT username, database, flagIN, destination_hostgroup, comment FROM main.pgsql_query_rules_fast_routing ORDER BY username, database, flagIN"; if (SQLite3_query_rules_fast_routing_resultset == NULL) { admindb->execute_statement(query2, &error2, &cols2, &affected_rows2, &resultset2); } else { // Cluster can pass SQLite3_query_rules_fast_routing_resultset , to absolutely speed up // the process and therefore there is no need to run any query resultset2 = SQLite3_query_rules_fast_routing_resultset; } if (error) { proxy_error("Error on %s : %s\n", query, error); } else if (error2) { proxy_error("Error on %s : %s\n", query2, error2); } else { fast_routing_hashmap_t fast_routing_hashmap(GloPgQPro->create_fast_routing_hashmap(resultset2)); #ifdef BENCHMARK_FASTROUTING_LOAD for (int i = 0; i < 10; i++) { #endif // BENCHMARK_FASTROUTING_LOAD // Computed resultsets checksums outside of critical sections uint64_t hash1 = 0; uint64_t hash2 = 0; if ( SQLite3_query_rules_resultset == nullptr || SQLite3_query_rules_fast_routing_resultset == nullptr ) { hash1 = resultset->raw_checksum(); hash2 = resultset2->raw_checksum(); } unsigned long long curtime1 = monotonic_time(); GloPgQPro->wrlock(); // Checksums are always generated - 'admin-checksum_*' deprecated { pthread_mutex_lock(&GloVars.checksum_mutex); char* buff = nullptr; char buf[20]; // If both the resultsets are supplied, then the supplied checksum is the already computed one. if ( SQLite3_query_rules_resultset == nullptr || SQLite3_query_rules_fast_routing_resultset == nullptr ) { hash1 += hash2; uint32_t d32[2]; memcpy(&d32, &hash1, sizeof(hash1)); sprintf(buf, "0x%0X%0X", d32[0], d32[1]); buff = buf; } else { buff = const_cast(checksum.c_str()); } GloVars.checksums_values.pgsql_query_rules.set_checksum(buff); GloVars.checksums_values.pgsql_query_rules.version++; time_t t = time(NULL); // Since the supplied checksum is the already computed one and both resultset are // supplied there is no need for comparsion, because we will be comparing it with itself. bool same_checksum = SQLite3_query_rules_resultset != nullptr && SQLite3_query_rules_fast_routing_resultset != nullptr; bool matching_checksums = same_checksum || (GloVars.checksums_values.pgsql_query_rules.checksum == checksum); if (epoch != 0 && checksum != "" && matching_checksums) { GloVars.checksums_values.pgsql_query_rules.epoch = epoch; } else { GloVars.checksums_values.pgsql_query_rules.epoch = t; } GloVars.epoch_version = t; GloVars.generate_global_checksum(); GloVars.checksums_values.updates_cnt++; pthread_mutex_unlock(&GloVars.checksum_mutex); proxy_info( "Computed checksum for 'LOAD PGSQL QUERY RULES TO RUNTIME' was '%s', with epoch '%llu'\n", GloVars.checksums_values.pgsql_query_rules.checksum, GloVars.checksums_values.pgsql_query_rules.epoch ); } rules_mem_sts_t prev_rules_data(GloPgQPro->reset_all(false)); QP_rule_t* nqpr; for (std::vector::iterator it = resultset->rows.begin(); it != resultset->rows.end(); ++it) { SQLite3_row* r = *it; if (r->fields[4]) { char* pct = NULL; if (strlen(r->fields[4]) >= INET6_ADDRSTRLEN) { proxy_error("Query rule with rule_id=%s has an invalid client_addr: %s\n", r->fields[0], r->fields[4]); continue; } pct = strchr(r->fields[4], '%'); if (pct) { // there is a wildcard if (strlen(pct) == 1) { // % is at the end of the string, good } else { proxy_error("Query rule with rule_id=%s has a wildcard that is not at the end of client_addr: %s\n", r->fields[0], r->fields[4]); continue; } } } nqpr = GloPgQPro->new_query_rule( atoi(r->fields[0]), // rule_id true, r->fields[1], // username r->fields[2], // schemaname atoi(r->fields[3]), // flagIN r->fields[4], // client_addr r->fields[5], // proxy_addr (r->fields[6] == NULL ? -1 : atol(r->fields[6])), // proxy_port r->fields[7], // digest r->fields[8], // match_digest r->fields[9], // match_pattern (atoi(r->fields[10]) == 1 ? true : false), // negate_match_pattern r->fields[11], // re_modifiers (r->fields[12] == NULL ? -1 : atol(r->fields[12])), // flagOUT r->fields[13], // replae_pattern (r->fields[14] == NULL ? -1 : atoi(r->fields[14])), // destination_hostgroup (r->fields[15] == NULL ? -1 : atol(r->fields[15])), // cache_ttl (r->fields[16] == NULL ? -1 : atol(r->fields[16])), // cache_empty_result (r->fields[17] == NULL ? -1 : atol(r->fields[17])), // cache_timeout (r->fields[18] == NULL ? -1 : atol(r->fields[18])), // reconnect (r->fields[19] == NULL ? -1 : atol(r->fields[19])), // timeout (r->fields[20] == NULL ? -1 : atol(r->fields[20])), // retries (r->fields[21] == NULL ? -1 : atol(r->fields[21])), // delay (r->fields[22] == NULL ? -1 : atol(r->fields[22])), // next_query_flagIN (r->fields[23] == NULL ? -1 : atol(r->fields[23])), // mirror_flagOUT (r->fields[24] == NULL ? -1 : atol(r->fields[24])), // mirror_hostgroup r->fields[25], // error_msg r->fields[26], // OK_msg (r->fields[27] == NULL ? -1 : atol(r->fields[27])), // sticky_conn (r->fields[28] == NULL ? -1 : atol(r->fields[28])), // multiplex (r->fields[29] == NULL ? -1 : atol(r->fields[29])), // log (atoi(r->fields[30]) == 1 ? true : false), r->fields[31], // attributes r->fields[32] // comment ); GloPgQPro->insert(nqpr, false); } GloPgQPro->sort(false); #ifdef BENCHMARK_FASTROUTING_LOAD // load a copy of resultset and resultset2 SQLite3_result* resultset3 = new SQLite3_result(resultset); GloPgQPro->save_query_rules(resultset3); SQLite3_result* resultset4 = new SQLite3_result(resultset2); GloPgQPro->load_fast_routing(resultset4); #else // load the original resultset and resultset2 GloPgQPro->save_query_rules(resultset); SQLite3_result* prev_fast_routing_resultset = GloPgQPro->load_fast_routing(fast_routing_hashmap); #endif // BENCHMARK_FASTROUTING_LOAD GloPgQPro->commit(); #ifdef BENCHMARK_FASTROUTING_LOAD } #endif // BENCHMARK_FASTROUTING_LOAD GloPgQPro->wrunlock(); unsigned long long curtime2 = monotonic_time(); unsigned long long elapsed_ms = (curtime2 / 1000) - (curtime1 / 1000); if (elapsed_ms > 5) { proxy_info("Query processor locked for %llums\n", curtime2 - curtime1); } // Free previous 'fast_routing' structures outside of critical section { delete prev_fast_routing_resultset; if (prev_rules_data.rules_fast_routing) { kh_destroy(khStrInt, prev_rules_data.rules_fast_routing); } if (prev_rules_data.rules_fast_routing___keys_values) { free(prev_rules_data.rules_fast_routing___keys_values); } __reset_rules(&prev_rules_data.query_rules); } } // if (resultset) delete resultset; // never delete it. GloPgQPro saves it // if (resultset2) delete resultset2; // never delete it. GloPgQPro saves it return NULL; } extern "C" ProxySQL_Admin * create_ProxySQL_Admin_func() { return new ProxySQL_Admin(); } extern "C" void destroy_Admin(ProxySQL_Admin * pa) { delete pa; } void ProxySQL_Admin::flush_error_log() { if (GloVars.global.foreground==false) { int outfd=0; int errfd=0; outfd=open(GloVars.errorlog, O_WRONLY | O_APPEND | O_CREAT , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (outfd>0) { dup2(outfd, STDOUT_FILENO); close(outfd); } else { proxy_error("Impossible to open file\n"); } errfd=open(GloVars.errorlog, O_WRONLY | O_APPEND | O_CREAT , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (errfd>0) { dup2(errfd, STDERR_FILENO); close(errfd); } else { proxy_error("Impossible to open file\n"); } } { struct utsname unameData; int rc; proxy_info("ProxySQL version %s\n", PROXYSQL_VERSION); rc=uname(&unameData); if (rc==0) { proxy_info("Detected OS: %s %s %s %s %s\n", unameData.sysname, unameData.nodename, unameData.release, unameData.version, unameData.machine); } if (binary_sha1) { proxy_info("ProxySQL SHA1 checksum: %s\n", binary_sha1); } } } void ProxySQL_Admin::load_proxysql_servers_to_runtime(bool _lock, const std::string& checksum, const time_t epoch) { // make sure that the caller has called mysql_servers_wrlock() char *error=NULL; int cols=0; int affected_rows=0; SQLite3_result *resultset=NULL; char *query=(char *)"SELECT hostname, port, weight, comment FROM proxysql_servers ORDER BY hostname, port"; proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); if (error) { proxy_error("Error on %s : %s\n", query, error); } else { GloProxyCluster->load_servers_list(resultset, _lock); // if (checksum_variables.checksum_mysql_query_rules) { pthread_mutex_lock(&GloVars.checksum_mutex); uint64_t hash1 = resultset->raw_checksum(); uint32_t d32[2]; char buf[20]; memcpy(&d32, &hash1, sizeof(hash1)); sprintf(buf,"0x%0X%0X", d32[0], d32[1]); GloVars.checksums_values.proxysql_servers.set_checksum(buf); GloVars.checksums_values.proxysql_servers.version++; time_t t = time(NULL); if (epoch != 0 && checksum != "" && GloVars.checksums_values.proxysql_servers.checksum == checksum) { GloVars.checksums_values.proxysql_servers.epoch = epoch; } else { GloVars.checksums_values.proxysql_servers.epoch = t; } GloVars.epoch_version = t; GloVars.generate_global_checksum(); GloVars.checksums_values.updates_cnt++; pthread_mutex_unlock(&GloVars.checksum_mutex); proxy_info( "Computed checksum for 'LOAD PROXYSQL SERVERS TO RUNTIME' was '%s', with epoch '%llu'\n", GloVars.checksums_values.proxysql_servers.checksum, GloVars.checksums_values.proxysql_servers.epoch ); // } } GloProxyCluster->update_table_proxysql_servers_for_monitor(resultset); // no need to release resultset resultset=NULL; } void ProxySQL_Admin::save_proxysql_servers_runtime_to_database(bool _runtime) { std::lock_guard lock(proxysql_servers_mutex); // make sure that the caller has called mysql_servers_wrlock() char *query=NULL; SQLite3_result *resultset=NULL; // dump proxysql_servers if (_runtime) { query=(char *)"DELETE FROM main.runtime_proxysql_servers"; } else { query=(char *)"DELETE FROM main.proxysql_servers"; } proxy_debug(PROXY_DEBUG_ADMIN, 4, "%s\n", query); admindb->execute(query); resultset=GloProxyCluster->dump_table_proxysql_servers(); if (resultset) { int rc; sqlite3_stmt *statement1=NULL; sqlite3_stmt *statement32=NULL; char *query1=NULL; char *query32=NULL; std::string query32s = ""; if (_runtime) { query1=(char *)"INSERT INTO runtime_proxysql_servers VALUES (?1, ?2, ?3, ?4)"; query32s = "INSERT INTO runtime_proxysql_servers VALUES " + generate_multi_rows_query(32,4); query32 = (char *)query32s.c_str(); } else { query1=(char *)"INSERT INTO proxysql_servers VALUES (?1, ?2, ?3, ?4)"; query32s = "INSERT INTO proxysql_servers VALUES " + generate_multi_rows_query(32,4); query32 = (char *)query32s.c_str(); } rc = admindb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, admindb); rc = admindb->prepare_v2(query32, &statement32); ASSERT_SQLITE_OK(rc, admindb); int row_idx=0; int max_bulk_row_idx=resultset->rows_count/32; max_bulk_row_idx=max_bulk_row_idx*32; for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r1=*it; int idx=row_idx%32; if (row_idxfields[0], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*4)+2, atoi(r1->fields[1])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*4)+3, atoi(r1->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement32, (idx*4)+4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); if (idx==31) { SAFE_SQLITE3_STEP2(statement32); rc=(*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, admindb); } } else { // single row rc=(*proxy_sqlite3_bind_text)(statement1, 1, r1->fields[0], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 2, atoi(r1->fields[1])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(statement1, 3, atoi(r1->fields[2])); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_text)(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, admindb); } row_idx++; } (*proxy_sqlite3_finalize)(statement1); (*proxy_sqlite3_finalize)(statement32); } if(resultset) delete resultset; resultset=NULL; } bool ProxySQL_Admin::flush_coredump_filters_database_to_runtime(SQLite3DB* db) { bool success = false; char *error=NULL; int cols=0; int affected_rows=0; SQLite3_result *resultset=NULL; const char* query = "SELECT filename, line FROM coredump_filters"; admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); if (error) { // LCOV_EXCL_START proxy_error("Error on %s : %s\n", query, error); assert(0); // LCOV_EXCL_STOP } else { std::unordered_set filters; for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { SQLite3_row *r=*it; std::string key; // we create a string with the row // remember the format is filename:line // no column can be null key = r->fields[0]; key += ":"; key += r->fields[1]; filters.emplace(std::move(key)); } proxy_coredump_load_filters(std::move(filters)); success = true; } if (resultset) delete resultset; return success; } void ProxySQL_Admin::dump_coredump_filter_values_table() { std::unordered_set filters; proxy_coredump_get_filters(filters); int rc; const char *query = "REPLACE INTO runtime_coredump_filters VALUES (?1,?2)"; sqlite3_stmt *stmt = NULL; rc = admindb->prepare_v2(query,&stmt); ASSERT_SQLITE_OK(rc, admindb); admindb->execute((char *)"BEGIN"); admindb->execute((char *)"DELETE FROM runtime_coredump_filters"); for (const auto& filter : filters) { char *filename=nullptr; char *lineno=nullptr; c_split_2(filter.c_str(), ":", &filename, &lineno); rc=(*proxy_sqlite3_bind_text)(stmt, 1, filename, -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_bind_int64)(stmt, 2, atoi(lineno)); ASSERT_SQLITE_OK(rc, admindb); SAFE_SQLITE3_STEP2(stmt); rc=(*proxy_sqlite3_clear_bindings)(stmt); ASSERT_SQLITE_OK(rc, admindb); rc=(*proxy_sqlite3_reset)(stmt); ASSERT_SQLITE_OK(rc, admindb); free(filename); free(lineno); } admindb->execute((char *)"COMMIT"); (*proxy_sqlite3_finalize)(stmt); } #ifdef TEST_GALERA void ProxySQL_Admin::enable_galera_testing() { proxy_info("Admin is enabling Galera Testing using SQLite3 Server and HGs from 2271 and 2290\n"); sqlite3_stmt *statement=NULL; unsigned int num_galera_servers = GloSQLite3Server->num_galera_servers[0]; int rc; mysql_servers_wrlock(); admindb->execute("DELETE FROM mysql_servers WHERE hostgroup_id BETWEEN 2271 AND 2300"); char *query=(char *)"INSERT INTO mysql_servers (hostgroup_id,hostname,use_ssl,comment) VALUES (?1, ?2, ?3, ?4)"; rc = admindb->prepare_v2(query, &statement); ASSERT_SQLITE_OK(rc, admindb); for (unsigned int j=1; j<4; j++) { proxy_info("Admin is enabling Galera Testing using SQLite3 Server and writer_HG %d\n" , 2260+j*10+1); for (unsigned int i=0; iexecute("INSERT INTO mysql_galera_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, comment) VALUES (2271, 2272, 2273, 2274, 0, 1, 1, 0, 'Automated Galera Testing Cluster 1')"); admindb->execute("INSERT INTO mysql_galera_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, comment) VALUES (2281, 2282, 2283, 2284, 0, 1, 1, 0, 'Automated Galera Testing Cluster 2')"); admindb->execute("INSERT INTO mysql_galera_hostgroups (writer_hostgroup, backup_writer_hostgroup, reader_hostgroup, offline_hostgroup, active, max_writers, writer_is_also_reader, max_transactions_behind, comment) VALUES (2291, 2292, 2293, 2294, 0, 1, 1, 0, 'Automated Galera Testing Cluster 3')"); admindb->execute("UPDATE mysql_galera_hostgroups SET active=1"); load_mysql_servers_to_runtime(); mysql_servers_wrunlock(); admindb->execute("UPDATE global_variables SET variable_value=200 WHERE variable_name='mysql-monitor_ping_interval'"); admindb->execute("UPDATE global_variables SET variable_value=3000 WHERE variable_name='mysql-monitor_ping_timeout'"); admindb->execute("UPDATE global_variables SET variable_value=200 WHERE variable_name='mysql-monitor_replication_lag_interval'"); admindb->execute("UPDATE global_variables SET variable_value=3000 WHERE variable_name='mysql-monitor_replication_lag_timeout'"); admindb->execute("UPDATE global_variables SET variable_value='percona.heartbeat' WHERE variable_name='mysql-monitor_replication_lag_use_percona_heartbeat'"); load_mysql_variables_to_runtime(); admindb->execute("INSERT INTO mysql_users (username,password,default_hostgroup) VALUES ('galera1','pass1',2271), ('galera2','pass2',2281), ('galera','pass3',2291)"); init_users(); } #endif // TEST_GALERA #ifdef TEST_AURORA void ProxySQL_Admin::enable_aurora_testing_populate_mysql_servers() { sqlite3_stmt *statement=NULL; unsigned int num_aurora_servers = GloSQLite3Server->num_aurora_servers[0]; admindb->execute("DELETE FROM mysql_servers WHERE hostgroup_id BETWEEN 1271 AND 1276"); char *query=(char *)"INSERT INTO mysql_servers (hostgroup_id,hostname,use_ssl,comment) VALUES (?1, ?2, ?3, ?4)"; int rc = admindb->prepare_v2(query, &statement); ASSERT_SQLITE_OK(rc, admindb); for (unsigned int j=1; j<4; j++) { proxy_info("Admin is enabling AWS Aurora Testing using SQLite3 Server and HGs 127%d and 127%d\n" , j*2-1 , j*2); for (unsigned int i=0; iexecute("INSERT INTO mysql_aws_aurora_hostgroups (writer_hostgroup, reader_hostgroup, active, domain_name, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, comment) VALUES (1271, 1272, 1, '.aws-test.com', 25, 1000, 90, 1, 1, 10, 20, 5, 'Automated Aurora Testing Cluster 1')"); admindb->execute("INSERT INTO mysql_aws_aurora_hostgroups (writer_hostgroup, reader_hostgroup, active, domain_name, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, comment) VALUES (1273, 1274, 1, '.cluster2.aws.test', 25, 1000, 90, 0, 1, 10, 20, 5, 'Automated Aurora Testing Cluster 2')"); admindb->execute("INSERT INTO mysql_aws_aurora_hostgroups (writer_hostgroup, reader_hostgroup, active, domain_name, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, comment) VALUES (1275, 1276, 1, '.aws-test.com', 25, 1000, 90, 0, 2, 10, 20, 5, 'Automated Aurora Testing Cluster 3')"); #else admindb->execute("INSERT INTO mysql_aws_aurora_hostgroups (writer_hostgroup, reader_hostgroup, active, domain_name, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, comment) VALUES (1271, 1272, 1, '.aws-test.com', 25, 120, 90, 1, 1, 10, 20, 5, 'Automated Aurora Testing Cluster 1')"); admindb->execute("INSERT INTO mysql_aws_aurora_hostgroups (writer_hostgroup, reader_hostgroup, active, domain_name, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, comment) VALUES (1273, 1274, 1, '.cluster2.aws.test', 25, 120, 90, 0, 1, 10, 20, 5, 'Automated Aurora Testing Cluster 2')"); admindb->execute("INSERT INTO mysql_aws_aurora_hostgroups (writer_hostgroup, reader_hostgroup, active, domain_name, max_lag_ms, check_interval_ms, check_timeout_ms, writer_is_also_reader, new_reader_weight, add_lag_ms, min_lag_ms, lag_num_checks, comment) VALUES (1275, 1276, 1, '.aws-test.com', 25, 120, 90, 0, 2, 10, 20, 5, 'Automated Aurora Testing Cluster 3')"); #endif admindb->execute("UPDATE mysql_aws_aurora_hostgroups SET active=1"); } void ProxySQL_Admin::enable_aurora_testing() { proxy_info("Admin is enabling AWS Aurora Testing using SQLite3 Server and HGs from 1271 to 1276\n"); mysql_servers_wrlock(); enable_aurora_testing_populate_mysql_servers(); enable_aurora_testing_populate_mysql_aurora_hostgroups(); load_mysql_servers_to_runtime(); mysql_servers_wrunlock(); admindb->execute("UPDATE global_variables SET variable_value=1000 WHERE variable_name='mysql-monitor_ping_interval'"); admindb->execute("UPDATE global_variables SET variable_value=3000 WHERE variable_name='mysql-monitor_ping_timeout'"); admindb->execute("UPDATE global_variables SET variable_value=1000 WHERE variable_name='mysql-monitor_replication_lag_interval'"); admindb->execute("UPDATE global_variables SET variable_value=3000 WHERE variable_name='mysql-monitor_replication_lag_timeout'"); admindb->execute("UPDATE global_variables SET variable_value='percona.heartbeat' WHERE variable_name='mysql-monitor_replication_lag_use_percona_heartbeat'"); load_mysql_variables_to_runtime(); admindb->execute("DELETE FROM mysql_users WHERE username LIKE '%aurora%'"); admindb->execute("INSERT INTO mysql_users (username,password,default_hostgroup) VALUES ('aurora1','pass1',1271), ('aurora2','pass2',1273), ('aurora3','pass3',1275)"); init_users(); admindb->execute("INSERT INTO mysql_query_rules (active, username, match_pattern, destination_hostgroup, apply) VALUES (1, 'aurora1', '^SELECT.*max_lag_ms', 1272, 1)"); admindb->execute("INSERT INTO mysql_query_rules (active, username, match_pattern, destination_hostgroup, apply) VALUES (1, 'aurora2', '^SELECT.*max_lag_ms', 1274, 1)"); admindb->execute("INSERT INTO mysql_query_rules (active, username, match_pattern, destination_hostgroup, apply) VALUES (1, 'aurora3', '^SELECT.*max_lag_ms', 1276, 1)"); load_mysql_query_rules_to_runtime(); } #endif // TEST_AURORA #ifdef TEST_GROUPREP void ProxySQL_Admin::enable_grouprep_testing() { proxy_info("Admin is enabling Group Replication Testing using SQLite3 Server and HGs from 3271 to 3274\n"); mysql_servers_wrlock(); admindb->execute("DELETE FROM mysql_servers WHERE hostgroup_id BETWEEN 3271 AND 3274"); admindb->execute("INSERT INTO mysql_servers (hostgroup_id, hostname, use_ssl, comment) VALUES (3272, '127.2.1.1', 0, '')"); admindb->execute("INSERT INTO mysql_servers (hostgroup_id, hostname, use_ssl, comment) VALUES (3273, '127.2.1.2', 0, '')"); admindb->execute("INSERT INTO mysql_servers (hostgroup_id, hostname, use_ssl, comment) VALUES (3273, '127.2.1.3', 0, '')"); admindb->execute("DELETE FROM mysql_group_replication_hostgroups"); admindb->execute("INSERT INTO mysql_group_replication_hostgroups " "(writer_hostgroup,backup_writer_hostgroup,reader_hostgroup,offline_hostgroup,active,max_writers," "writer_is_also_reader,max_transactions_behind) VALUES (3272,3274,3273,3271,1,1,1,0);"); load_mysql_servers_to_runtime(); mysql_servers_wrunlock(); admindb->execute("UPDATE global_variables SET variable_value=5000 WHERE variable_name='mysql-monitor_groupreplication_healthcheck_interval'"); admindb->execute("UPDATE global_variables SET variable_value=800 WHERE variable_name='mysql-monitor_groupreplication_healthcheck_timeout'"); admindb->execute("UPDATE global_variables SET variable_value=3 WHERE variable_name='mysql-monitor_groupreplication_healthcheck_max_timeout_count'"); admindb->execute("UPDATE global_variables SET variable_value=3 WHERE variable_name='mysql-monitor_groupreplication_max_transactions_behind_count'"); load_mysql_variables_to_runtime(); admindb->execute("DELETE FROM mysql_users WHERE username='grouprep1'"); admindb->execute("INSERT INTO mysql_users (username,password,default_hostgroup) VALUES ('grouprep1','pass1',3272)"); init_users(); load_mysql_query_rules_to_runtime(); } #endif // TEST_GROUPREP #ifdef TEST_READONLY void ProxySQL_Admin::enable_readonly_testing() { proxy_info("Admin is enabling Read Only Testing using SQLite3 Server and HGs from 4201 to 4800\n"); mysql_servers_wrlock(); string q; q = "DELETE FROM mysql_servers WHERE hostgroup_id BETWEEN 4201 AND 4800"; admindb->execute(q.c_str()); /* * NOTE: This section can be uncomment for manual testing. It populates the `mysql_servers` * and `mysql_replication_hostgroups`. */ // ************************************************************************************** // for (int i=1; i < 4; i++) { // for (int j=2; j<100; j+=2) { // for (int k=1; k<5; k++) { // q = "INSERT INTO mysql_servers (hostgroup_id, hostname, use_ssl, comment) VALUES (" + std::to_string(4000+i*200+j) + ", '127.5."+ std::to_string(i) +"." + std::to_string(j*2+k) + "', 0, '')"; // admindb->execute(q.c_str()); // } // q = "INSERT INTO mysql_replication_hostgroups(writer_hostgroup, reader_hostgroup) VALUES (" + std::to_string(4000+i*200+j-1) + "," + std::to_string(4000+i*200+j) + ")"; // admindb->execute(q.c_str()); // } // } // ************************************************************************************** load_mysql_servers_to_runtime(); mysql_servers_wrunlock(); } #endif // TEST_READONLY #ifdef TEST_REPLICATIONLAG void ProxySQL_Admin::enable_replicationlag_testing() { proxy_info("Admin is enabling Replication Lag Testing using SQLite3 Server and HGs from 5201 to 5800\n"); mysql_servers_wrlock(); admindb->execute("DELETE FROM mysql_servers WHERE hostgroup_id BETWEEN 5201 AND 5800"); load_mysql_servers_to_runtime(); mysql_servers_wrunlock(); } #endif // TEST_REPLICATIONLAG