Merge remote-tracking branch 'remotes/Master_POSTGRES/v2.x_postgres' into v2.x_postgres_backend

Conflicts:
	lib/PgSQL_HostGroups_Manager.cpp
	lib/PgSQL_Thread.cpp
v2.x_pg_PrepStmtBase_240714
Rahim Kanji 2 years ago
commit fb0d8c0b69

File diff suppressed because it is too large Load Diff

@ -121,8 +121,28 @@ class Base_Session {
void housekeeping_before_pkts();
virtual void create_new_session_and_reset_connection(DS *_myds) = 0;
using TypeConn = typename std::conditional<
std::is_same_v<S, MySQL_Session>, MySQL_Connection, PgSQL_Connection
>::type;
void update_expired_conns(const std::vector<std::function<bool(TypeConn*)>>&);
void set_unhealthy();
unsigned int NumActiveTransactions(bool check_savpoint=false);
bool HasOfflineBackends();
bool SetEventInOfflineBackends();
/**
* @brief Finds one active transaction in the current backend connections.
* @details Since only one connection is returned, if the session holds multiple backend connections with
* potential transactions, the priority is:
* 1. Connections flagged with 'SERVER_STATUS_IN_TRANS', or 'autocommit=0' in combination with
* 'autocommit_false_is_transaction'.
* 2. Connections with 'autocommit=0' holding a 'SAVEPOINT'.
* 3. Connections with 'unknown transaction status', e.g: connections with errors.
* @param check_savepoint Used to also check for connections holding savepoints. See MySQL bug
* https://bugs.mysql.com/bug.php?id=107875.
* @returns The hostgroup in which the connection was found, -1 in case no connection is found.
*/
int FindOneActiveTransaction(bool check_savepoint=false);
};
#endif // CLASS_BASE_SESSION_H

@ -35,8 +35,8 @@ namespace nlohmann { class json; }
//#define STRESSTEST_POOL
#endif // DEBUG
#define MHM_PTHREAD_MUTEX
#include "Base_HostGroups_Manager.h"
// we have 2 versions of the same tables: with (debug) and without (no debug) checks
#ifdef DEBUG
@ -273,68 +273,16 @@ private:
enum MySerStatus status;
};
class MySrvList { // MySQL Server List
private:
MyHGC *myhgc;
int find_idx(MySrvC *);
class MySrvList: public BaseSrvList<MyHGC> { // MySQL Server List
public:
PtrArray *servers;
unsigned int cnt() { return servers->len; }
MySrvList(MyHGC *);
~MySrvList();
void add(MySrvC *);
void remove(MySrvC *);
MySrvC * idx(unsigned int i) {return (MySrvC *)servers->index(i); }
MySrvList(MyHGC* hgc) : BaseSrvList<MyHGC>(hgc) {}
};
class MyHGC { // MySQL Host Group Container
class MyHGC: public BaseHGC<MyHGC> {
public:
unsigned int hid;
std::atomic<uint32_t> num_online_servers;
time_t last_log_time_num_online_servers;
unsigned long long current_time_now;
uint32_t new_connections_now;
MySrvList *mysrvs;
struct { // this is a series of attributes specific for each hostgroup
char * init_connect;
char * comment;
char * ignore_session_variables_text; // this is the original version (text format) of ignore_session_variables
uint32_t max_num_online_servers;
uint32_t throttle_connections_per_sec;
int32_t monitor_slave_lag_when_null;
int8_t autocommit;
int8_t free_connections_pct;
int8_t handle_warnings;
bool multiplex;
bool connection_warming;
bool configured; // this variable controls if attributes are configured or not. If not configured, they do not apply
bool initialized; // this variable controls if attributes were ever configured or not. Used by reset_attributes()
nlohmann::json * ignore_session_variables_json = NULL; // the JSON format of ignore_session_variables
} attributes;
struct {
int64_t weight;
int64_t max_connections;
int32_t use_ssl;
} servers_defaults;
void reset_attributes();
inline
bool handle_warnings_enabled() const {
return attributes.configured == true && attributes.handle_warnings != -1 ? attributes.handle_warnings : mysql_thread___handle_warnings;
}
inline
int32_t get_monitor_slave_lag_when_null() const {
return attributes.configured == true && attributes.monitor_slave_lag_when_null != -1 ? attributes.monitor_slave_lag_when_null : mysql_thread___monitor_slave_lag_when_null;
}
MyHGC(int);
~MyHGC();
MyHGC(int _hid) : BaseHGC<MyHGC>(_hid) {}
MySrvC *get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_lag_ms, MySQL_Session *sess);
void refresh_online_server_count();
void log_num_online_server_count_error();
inline
bool online_servers_within_threshold() const {
if (num_online_servers.load(std::memory_order_relaxed) <= attributes.max_num_online_servers) return true;
return false;
}
};
class Group_Replication_Info {
@ -600,19 +548,16 @@ struct srv_opts_t {
int32_t use_ssl;
};
class MySQL_HostGroups_Manager {
class MySQL_HostGroups_Manager : public Base_HostGroups_Manager<MyHGC> {
private:
#if 0
SQLite3DB *admindb;
SQLite3DB *mydb;
pthread_mutex_t readonly_mutex;
std::set<std::string> read_only_set1;
std::set<std::string> read_only_set2;
#ifdef MHM_PTHREAD_MUTEX
pthread_mutex_t lock;
#else
rwlock_t rwlock;
#endif
#endif // 0
enum HGM_TABLES {
MYSQL_SERVERS_V2 = 0,
MYSQL_REPLICATION_HOSTGROUPS,
@ -727,15 +672,16 @@ class MySQL_HostGroups_Manager {
uint64_t hgsm_mysql_replication_hostgroups_checksum = 0;
#if 0
PtrArray *MyHostGroups;
std::unordered_map<unsigned int, MyHGC *>MyHostGroups_map;
#endif // 0
std::mutex Servers_SSL_Params_map_mutex;
std::unordered_map<std::string, MySQLServers_SslParams> Servers_SSL_Params_map;
#if 0
MyHGC * MyHGC_find(unsigned int);
MyHGC * MyHGC_create(unsigned int);
#endif // 0
void add(MySrvC *, unsigned int);
void purge_mysql_servers_table();
void generate_mysql_servers_table(int *_onlyhg=NULL);
@ -952,11 +898,13 @@ class MySQL_HostGroups_Manager {
MySQL_HostGroups_Manager();
~MySQL_HostGroups_Manager();
void init();
#if 0
void wrlock();
void wrunlock();
#ifdef DEBUG
bool is_locked = false;
#endif
#endif // 0
int servers_add(SQLite3_result *resultset);
/**
* @brief Generates a new global checksum for module 'mysql_servers_v2' using the provided hash.
@ -1041,7 +989,7 @@ class MySQL_HostGroups_Manager {
void save_incoming_mysql_table(SQLite3_result *, const string&);
SQLite3_result* get_current_mysql_table(const string& name);
SQLite3_result * execute_query(char *query, char **error);
//SQLite3_result * execute_query(char *query, char **error);
/**
* @brief Creates a resultset with the current full content of the target table.
* @param string The target table. Valid values are:
@ -1070,7 +1018,6 @@ class MySQL_HostGroups_Manager {
* @param lock When supplied the function calls 'wrlock()' and 'wrunlock()' functions for accessing the db.
*/
void update_table_mysql_servers_for_monitor(bool lock=false);
MyHGC * MyHGC_lookup(unsigned int);
void MyConn_add_to_pool(MySQL_Connection *);
/**

@ -268,7 +268,6 @@ class MySQL_Session: public Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL
void handler_WCD_SS_MCQ_qpo_OK_msg(PtrSize_t *pkt);
void handler_WCD_SS_MCQ_qpo_error_msg(PtrSize_t *pkt);
void handler_WCD_SS_MCQ_qpo_LargePacket(PtrSize_t *pkt);
// int handler_WCD_SS_MCQ_qpo_Parse_SQL_LOG_BIN(PtrSize_t *pkt, bool *lock_hostgroup, unsigned int nTrx, string& nq);
public:
bool handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, const char *var_name, const char *var_value, bool no_quote=false, bool set_transaction=false);
@ -387,7 +386,7 @@ class MySQL_Session: public Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL
MySQL_Session();
~MySQL_Session();
void set_unhealthy();
//void set_unhealthy();
void set_status(enum session_status e);
int handler();
@ -400,9 +399,9 @@ class MySQL_Session: public Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL
void SQLite3_to_MySQL(SQLite3_result *, char *, int , MySQL_Protocol *, bool in_transaction=false, bool deprecate_eof_active=false) override;
void MySQL_Result_to_MySQL_wire(MYSQL *mysql, MySQL_ResultSet *MyRS, unsigned int warning_count, MySQL_Data_Stream *_myds=NULL);
void MySQL_Stmt_Result_to_MySQL_wire(MYSQL_STMT *stmt, MySQL_Connection *myconn);
unsigned int NumActiveTransactions(bool check_savpoint=false);
bool HasOfflineBackends();
bool SetEventInOfflineBackends();
//unsigned int NumActiveTransactions(bool check_savpoint=false);
//bool HasOfflineBackends();
//bool SetEventInOfflineBackends();
/**
* @brief Finds one active transaction in the current backend connections.
* @details Since only one connection is returned, if the session holds multiple backend connections with
@ -415,7 +414,7 @@ class MySQL_Session: public Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL
* https://bugs.mysql.com/bug.php?id=107875.
* @returns The hostgroup in which the connection was found, -1 in case no connection is found.
*/
int FindOneActiveTransaction(bool check_savepoint=false);
//int FindOneActiveTransaction(bool check_savepoint=false);
unsigned long long IdleTime();
//void reset_all_backends();
@ -423,7 +422,7 @@ class MySQL_Session: public Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL
void Memory_Stats();
void create_new_session_and_reset_connection(MySQL_Data_Stream *_myds) override;
bool handle_command_query_kill(PtrSize_t *);
void update_expired_conns(const std::vector<std::function<bool(MySQL_Connection*)>>&);
//void update_expired_conns(const std::vector<std::function<bool(MySQL_Connection*)>>&);
/**
* @brief Performs the final operations after current query has finished to be executed. It updates the session
* 'transaction_persistent_hostgroup', and updates the 'MySQL_Data_Stream' and 'MySQL_Connection' before

@ -35,8 +35,8 @@ namespace nlohmann { class json; }
//#define STRESSTEST_POOL
#endif // DEBUG
#define MHM_PTHREAD_MUTEX
#include "Base_HostGroups_Manager.h"
// we have 2 versions of the same tables: with (debug) and without (no debug) checks
#ifdef DEBUG
@ -240,122 +240,17 @@ class PgSQL_SrvC { // MySQL Server Container
}
};
class PgSQL_SrvList { // MySQL Server List
private:
PgSQL_HGC *myhgc;
int find_idx(PgSQL_SrvC *);
public:
PtrArray *servers;
unsigned int cnt() { return servers->len; }
PgSQL_SrvList(PgSQL_HGC *);
~PgSQL_SrvList();
void add(PgSQL_SrvC *);
void remove(PgSQL_SrvC *);
PgSQL_SrvC * idx(unsigned int i) {return (PgSQL_SrvC *)servers->index(i); }
};
class PgSQL_HGC { // MySQL Host Group Container
public:
unsigned int hid;
unsigned long long current_time_now;
uint32_t new_connections_now;
PgSQL_SrvList *mysrvs;
struct { // this is a series of attributes specific for each hostgroup
char * init_connect;
char * comment;
char * ignore_session_variables_text; // this is the original version (text format) of ignore_session_variables
uint32_t max_num_online_servers;
uint32_t throttle_connections_per_sec;
int8_t autocommit;
int8_t free_connections_pct;
int8_t handle_warnings;
bool multiplex;
bool connection_warming;
bool configured; // this variable controls if attributes are configured or not. If not configured, they do not apply
bool initialized; // this variable controls if attributes were ever configured or not. Used by reset_attributes()
nlohmann::json * ignore_session_variables_json = NULL; // the JSON format of ignore_session_variables
} attributes;
struct {
int64_t weight;
int64_t max_connections;
int32_t use_ssl;
} servers_defaults;
void reset_attributes();
inline
bool handle_warnings_enabled() const {
return attributes.configured == true && attributes.handle_warnings != -1 ? attributes.handle_warnings : mysql_thread___handle_warnings;
}
PgSQL_HGC(int);
~PgSQL_HGC();
PgSQL_SrvC *get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_lag_ms, PgSQL_Session *sess);
};
class PgSQL_Group_Replication_Info {
class PgSQL_SrvList: public BaseSrvList<PgSQL_HGC> {
public:
int writer_hostgroup;
int backup_writer_hostgroup;
int reader_hostgroup;
int offline_hostgroup;
int max_writers;
int max_transactions_behind;
char *comment;
bool active;
int writer_is_also_reader;
bool __active;
bool need_converge; // this is set to true on LOAD PgSQL SERVERS TO RUNTIME . This ensure that checks wil take an action
int current_num_writers;
int current_num_backup_writers;
int current_num_readers;
int current_num_offline;
PgSQL_Group_Replication_Info(int w, int b, int r, int o, int mw, int mtb, bool _a, int _w, char *c);
bool update(int b, int r, int o, int mw, int mtb, bool _a, int _w, char *c);
~PgSQL_Group_Replication_Info();
PgSQL_SrvList(PgSQL_HGC* hgc) : BaseSrvList<PgSQL_HGC>(hgc) {}
friend class PgSQL_HGC;
};
class PgSQL_Galera_Info {
public:
int writer_hostgroup;
int backup_writer_hostgroup;
int reader_hostgroup;
int offline_hostgroup;
int max_writers;
int max_transactions_behind;
char *comment;
bool active;
int writer_is_also_reader;
bool __active;
bool need_converge; // this is set to true on LOAD PgSQL SERVERS TO RUNTIME . This ensure that checks wil take an action
int current_num_writers;
int current_num_backup_writers;
int current_num_readers;
int current_num_offline;
PgSQL_Galera_Info(int w, int b, int r, int o, int mw, int mtb, bool _a, int _w, char *c);
bool update(int b, int r, int o, int mw, int mtb, bool _a, int _w, char *c);
~PgSQL_Galera_Info();
};
class PgSQL_AWS_Aurora_Info {
class PgSQL_HGC: public BaseHGC<PgSQL_HGC> {
public:
int writer_hostgroup;
int reader_hostgroup;
int aurora_port;
int max_lag_ms;
int add_lag_ms;
int min_lag_ms;
int lag_num_checks;
int check_interval_ms;
int check_timeout_ms;
int writer_is_also_reader;
int new_reader_weight;
// TODO
// add intermediary status value, for example the last check time
char * domain_name;
char * comment;
bool active;
bool __active;
PgSQL_AWS_Aurora_Info(int w, int r, int _port, char *_end_addr, int maxl, int al, int minl, int lnc, int ci, int ct, bool _a, int wiar, int nrw, char *c);
bool update(int r, int _port, char *_end_addr, int maxl, int al, int minl, int lnc, int ci, int ct, bool _a, int wiar, int nrw, char *c);
~PgSQL_AWS_Aurora_Info();
PgSQL_HGC(int _hid) : BaseHGC<PgSQL_HGC>(_hid) {}
PgSQL_SrvC *get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_lag_ms, PgSQL_Session *sess);
};
struct PgSQL_p_hg_counter {
@ -490,19 +385,16 @@ struct PgSQL_srv_opts_t {
int32_t use_ssl;
};
class PgSQL_HostGroups_Manager {
private:
class PgSQL_HostGroups_Manager : public Base_HostGroups_Manager<PgSQL_HGC> {
#if 0
SQLite3DB *admindb;
SQLite3DB *mydb;
pthread_mutex_t readonly_mutex;
std::set<std::string> read_only_set1;
std::set<std::string> read_only_set2;
#ifdef MHM_PTHREAD_MUTEX
pthread_mutex_t lock;
#else
rwlock_t rwlock;
#endif
#endif // 0
private:
enum HGM_TABLES {
PgSQL_SERVERS_V2 = 0,
PgSQL_REPLICATION_HOSTGROUPS,
@ -615,12 +507,13 @@ class PgSQL_HostGroups_Manager {
*/
uint64_t hgsm_pgsql_replication_hostgroups_checksum = 0;
#if 0
PtrArray *MyHostGroups;
std::unordered_map<unsigned int, PgSQL_HGC *>MyHostGroups_map;
PgSQL_HGC * MyHGC_find(unsigned int);
PgSQL_HGC * MyHGC_create(unsigned int);
#endif // 0
void add(PgSQL_SrvC *, unsigned int);
void purge_pgsql_servers_table();
@ -679,10 +572,6 @@ class PgSQL_HostGroups_Manager {
* @brief Update the prometheus "connection_pool" counters.
*/
void p_update_connection_pool();
/**
* @brief Update the "stats_pgsql_gtid_executed" counters.
*/
void p_update_pgsql_gtid_executed();
void p_update_connection_pool_update_counter(
const std::string& endpoint_id, const std::map<std::string, std::string>& labels,
@ -801,8 +690,8 @@ class PgSQL_HostGroups_Manager {
PgSQL_HostGroups_Manager();
~PgSQL_HostGroups_Manager();
void init();
void wrlock();
void wrunlock();
//void wrlock();
//void wrunlock();
int servers_add(SQLite3_result *resultset);
/**
* @brief Generates a new global checksum for module 'pgsql_servers_v2' using the provided hash.
@ -883,7 +772,7 @@ class PgSQL_HostGroups_Manager {
void save_incoming_pgsql_table(SQLite3_result *, const string&);
SQLite3_result* get_current_pgsql_table(const string& name);
SQLite3_result * execute_query(char *query, char **error);
//SQLite3_result * execute_query(char *query, char **error);
/**
* @brief Creates a resultset with the current full content of the target table.
* @param string The target table. Valid values are:
@ -909,7 +798,6 @@ class PgSQL_HostGroups_Manager {
* @param lock When supplied the function calls 'wrlock()' and 'wrunlock()' functions for accessing the db.
*/
void update_table_pgsql_servers_for_monitor(bool lock=false);
PgSQL_HGC * MyHGC_lookup(unsigned int);
void MyConn_add_to_pool(PgSQL_Connection *);
/**
@ -962,10 +850,6 @@ class PgSQL_HostGroups_Manager {
void set_server_current_latency_us(char *hostname, int port, unsigned int _current_latency_us);
unsigned long long Get_Memory_Stats();
SQLite3_result * get_stats_pgsql_gtid_executed();
void generate_pgsql_gtid_executed_tables();
bool gtid_exists(PgSQL_SrvC *mysrvc, char * gtid_uuid, uint64_t gtid_trxid);
SQLite3_result *SQL3_Get_ConnPool_Stats();
void increase_reset_counter();

@ -246,7 +246,6 @@ private:
void handler_WCD_SS_MCQ_qpo_OK_msg(PtrSize_t* pkt);
void handler_WCD_SS_MCQ_qpo_error_msg(PtrSize_t* pkt);
void handler_WCD_SS_MCQ_qpo_LargePacket(PtrSize_t* pkt);
// int handler_WCD_SS_MCQ_qpo_Parse_SQL_LOG_BIN(PtrSize_t *pkt, bool *lock_hostgroup, unsigned int nTrx, string& nq);
public:
bool handler_again___status_SETTING_GENERIC_VARIABLE(int* _rc, const char* var_name, const char* var_value, bool no_quote = false, bool set_transaction = false);
@ -365,7 +364,7 @@ public:
PgSQL_Session();
~PgSQL_Session();
void set_unhealthy();
//void set_unhealthy();
void set_status(enum session_status e);
int handler();
@ -378,9 +377,9 @@ public:
void SQLite3_to_MySQL(SQLite3_result*, char*, int, MySQL_Protocol*, bool in_transaction = false, bool deprecate_eof_active = false) override;
void PgSQL_Result_to_PgSQL_wire(PgSQL_Connection* conn, PgSQL_Data_Stream* _myds = NULL);
void MySQL_Stmt_Result_to_MySQL_wire(MYSQL_STMT* stmt, PgSQL_Connection* myconn);
unsigned int NumActiveTransactions(bool check_savpoint = false);
bool HasOfflineBackends();
bool SetEventInOfflineBackends();
//unsigned int NumActiveTransactions(bool check_savpoint = false);
//bool HasOfflineBackends();
//bool SetEventInOfflineBackends();
/**
* @brief Finds one active transaction in the current backend connections.
* @details Since only one connection is returned, if the session holds multiple backend connections with
@ -393,7 +392,7 @@ public:
* https://bugs.mysql.com/bug.php?id=107875.
* @returns The hostgroup in which the connection was found, -1 in case no connection is found.
*/
int FindOneActiveTransaction(bool check_savepoint = false);
//int FindOneActiveTransaction(bool check_savepoint = false);
unsigned long long IdleTime();
//void reset_all_backends();
@ -401,7 +400,7 @@ public:
void Memory_Stats();
void create_new_session_and_reset_connection(PgSQL_Data_Stream* _myds) override;
bool handle_command_query_kill(PtrSize_t*);
void update_expired_conns(const std::vector<std::function<bool(PgSQL_Connection*)>>&);
//void update_expired_conns(const std::vector<std::function<bool(PgSQL_Connection*)>>&);
/**
* @brief Performs the final operations after current query has finished to be executed. It updates the session
* 'transaction_persistent_hostgroup', and updates the 'PgSQL_Data_Stream' and 'PgSQL_Connection' before

@ -617,6 +617,8 @@ bool ProxySQL_Admin::init(const bootstrap_info_t& bootstrap_info) {
insert_into_tables_defs(tables_defs_config, "pgsql_ldap_mapping", ADMIN_SQLITE_TABLE_PGSQL_LDAP_MAPPING);
insert_into_tables_defs(tables_defs_config, "pgsql_query_rules", ADMIN_SQLITE_TABLE_PGSQL_QUERY_RULES);
insert_into_tables_defs(tables_defs_config, "pgsql_query_rules_fast_routing", ADMIN_SQLITE_TABLE_PGSQL_QUERY_RULES_FAST_ROUTING);
insert_into_tables_defs(tables_defs_config, "pgsql_hostgroup_attributes", ADMIN_SQLITE_TABLE_PGSQL_HOSTGROUP_ATTRIBUTES);
insert_into_tables_defs(tables_defs_config, "pgsql_replication_hostgroups", ADMIN_SQLITE_TABLE_PGSQL_REPLICATION_HOSTGROUPS);
insert_into_tables_defs(tables_defs_config, "pgsql_firewall_whitelist_users", ADMIN_SQLITE_TABLE_PGSQL_FIREWALL_WHITELIST_USERS);
insert_into_tables_defs(tables_defs_config, "pgsql_firewall_whitelist_rules", ADMIN_SQLITE_TABLE_PGSQL_FIREWALL_WHITELIST_RULES);
insert_into_tables_defs(tables_defs_config, "pgsql_firewall_whitelist_sqli_fingerprints", ADMIN_SQLITE_TABLE_PGSQL_FIREWALL_WHITELIST_SQLI_FINGERPRINTS);

@ -3469,6 +3469,21 @@ void admin_session_handler(Client_Session<T> sess, void *_pa, PtrSize_t *pkt) {
goto __run_query;
}
if (query_no_space_length == strlen("SHOW PGSQL VARIABLES") && !strncasecmp("SHOW PGSQL VARIABLES", query_no_space, query_no_space_length)) {
l_free(query_length, query);
query = l_strdup("SELECT variable_name AS Variable_name, variable_value AS Value FROM global_variables WHERE variable_name LIKE 'pgsql-\%' ORDER BY variable_name");
query_length = strlen(query) + 1;
goto __run_query;
}
/*if (query_no_space_length == strlen("SHOW PGSQL STATUS") && !strncasecmp("SHOW PGSQL STATUS", query_no_space, query_no_space_length)) {
l_free(query_length, query);
query = l_strdup("SELECT Variable_Name AS Variable_name, Variable_Value AS Value FROM stats_pgsql_global ORDER BY variable_name");
query_length = strlen(query) + 1;
GloAdmin->stats___mysql_global();
goto __run_query;
}*/
strA=(char *)"SHOW CREATE TABLE ";
strB=(char *)"SELECT name AS 'table' , REPLACE(REPLACE(sql,' , ', X'2C0A20202020'),'CREATE TABLE %s (','CREATE TABLE %s ('||X'0A20202020') AS 'Create Table' FROM %s.sqlite_master WHERE type='table' AND name='%s'";
strAl=strlen(strA);

@ -0,0 +1,131 @@
#include "../deps/json/json.hpp"
using json = nlohmann::json;
#define PROXYJSON
#include "Base_HostGroups_Manager.h"
template BaseHGC<MyHGC>::BaseHGC(int);
template BaseHGC<MyHGC>::~BaseHGC();
template void BaseHGC<MyHGC>::log_num_online_server_count_error();
template void BaseHGC<MyHGC>::reset_attributes();
template void BaseHGC<MyHGC>::refresh_online_server_count();
template BaseHGC<PgSQL_HGC>::BaseHGC(int);
template BaseHGC<PgSQL_HGC>::~BaseHGC();
template void BaseHGC<PgSQL_HGC>::log_num_online_server_count_error();
template void BaseHGC<PgSQL_HGC>::reset_attributes();
template void BaseHGC<PgSQL_HGC>::refresh_online_server_count();
template<typename HGC>
using TypeSrvC = typename std::conditional<
std::is_same_v<HGC, MyHGC>, MySrvC, PgSQL_SrvC
>::type;
template<typename HGC>
using TypeSess = typename std::conditional<
std::is_same_v<HGC, MyHGC>, MySQL_Session, PgSQL_Session
>::type;
#include "MySQL_HostGroups_Manager.h"
#ifdef TEST_AURORA
if constexpr (std::is_same_v<HGC, MyHGC>) {
static unsigned long long array_mysrvc_total = 0;
static unsigned long long array_mysrvc_cands = 0;
}
#endif // TEST_AURORA
extern MySQL_Threads_Handler *GloMTH;
template<typename HGC>
BaseHGC<HGC>::BaseHGC(int _hid) {
hid=_hid;
if constexpr (std::is_same_v<HGC, MyHGC>) {
mysrvs=new MySrvList(static_cast<HGC*>(this));
} else if constexpr (std::is_same_v<HGC, PgSQL_HGC>) {
mysrvs=new PgSQL_SrvList(static_cast<HGC*>(this));
} else {
assert(0);
}
current_time_now = 0;
new_connections_now = 0;
attributes.initialized = false;
reset_attributes();
// Uninitialized server defaults. Should later be initialized via 'mysql_hostgroup_attributes'.
servers_defaults.weight = -1;
servers_defaults.max_connections = -1;
servers_defaults.use_ssl = -1;
num_online_servers.store(0, std::memory_order_relaxed);;
last_log_time_num_online_servers = 0;
}
template<typename HGC>
void BaseHGC<HGC>::reset_attributes() {
if (attributes.initialized == false) {
attributes.init_connect = NULL;
attributes.comment = NULL;
attributes.ignore_session_variables_text = NULL;
}
attributes.initialized = true;
attributes.configured = false;
attributes.max_num_online_servers = 1000000;
attributes.throttle_connections_per_sec = 1000000;
attributes.autocommit = -1;
attributes.free_connections_pct = 10;
attributes.handle_warnings = -1;
attributes.monitor_slave_lag_when_null = -1;
attributes.multiplex = true;
attributes.connection_warming = false;
free(attributes.init_connect);
attributes.init_connect = NULL;
free(attributes.comment);
attributes.comment = NULL;
free(attributes.ignore_session_variables_text);
attributes.ignore_session_variables_text = NULL;
if (attributes.ignore_session_variables_json) {
delete attributes.ignore_session_variables_json;
attributes.ignore_session_variables_json = NULL;
}
}
template<typename HGC>
BaseHGC<HGC>::~BaseHGC() {
reset_attributes(); // free all memory
delete mysrvs;
}
template<typename HGC>
void BaseHGC<HGC>::refresh_online_server_count() {
if (__sync_fetch_and_add(&glovars.shutdown, 0) != 0)
return;
#ifdef DEBUG
assert(MyHGM->is_locked);
#endif
unsigned int online_servers_count = 0;
if constexpr (std::is_same_v<HGC, MyHGC>) { // FIXME: this logic for now is enabled only for MySQL
for (unsigned int i = 0; i < mysrvs->servers->len; i++) {
TypeSrvC* mysrvc = (TypeSrvC*)mysrvs->servers->index(i);
if (mysrvc->get_status() == MYSQL_SERVER_STATUS_ONLINE) {
online_servers_count++;
}
}
}
num_online_servers.store(online_servers_count, std::memory_order_relaxed);
}
template<typename HGC>
void BaseHGC<HGC>::log_num_online_server_count_error() {
const time_t curtime = time(NULL);
// if this is the first time the method is called or if more than 10 seconds have passed since the last log
if (last_log_time_num_online_servers == 0 ||
((curtime - last_log_time_num_online_servers) > 10)) {
last_log_time_num_online_servers = curtime;
proxy_error(
"Number of online servers detected in a hostgroup exceeds the configured maximum online servers. hostgroup:%u, num_online_servers:%u, max_online_servers:%u\n",
hid, num_online_servers.load(std::memory_order_relaxed), attributes.max_num_online_servers);
}
}

@ -0,0 +1,72 @@
#include "Base_HostGroups_Manager.h"
template<typename HGC>
using TypeSrvC = typename std::conditional<
std::is_same_v<HGC, MyHGC>, MySrvC, PgSQL_SrvC
>::type;
template BaseSrvList<MyHGC>::BaseSrvList(MyHGC*);
template BaseSrvList<MyHGC>::~BaseSrvList();
template void BaseSrvList<MyHGC>::add(MySrvC*);
template BaseSrvList<PgSQL_HGC>::BaseSrvList(PgSQL_HGC*);
template BaseSrvList<PgSQL_HGC>::~BaseSrvList();
template void BaseSrvList<PgSQL_HGC>::add(PgSQL_SrvC*);
template<typename HGC>
BaseSrvList<HGC>::BaseSrvList(HGC *_myhgc) {
myhgc=_myhgc;
servers=new PtrArray();
}
template<typename HGC>
void BaseSrvList<HGC>::add(TypeSrvC *s) {
if (s->myhgc==NULL) {
s->myhgc=myhgc;
}
servers->add(s);
if constexpr (std::is_same_v<HGC, MyHGC>) {
myhgc->refresh_online_server_count();
} else if constexpr (std::is_same_v<HGC, PgSQL_HGC>) {
//myhgc->refresh_online_server_count(); FIXME: not implemented
} else {
assert(0);
}
}
template<typename HGC>
int BaseSrvList<HGC>::find_idx(TypeSrvC *s) {
for (unsigned int i=0; i<servers->len; i++) {
TypeSrvC *mysrv=(TypeSrvC *)servers->index(i);
if (mysrv==s) {
return (unsigned int)i;
}
}
return -1;
}
template<typename HGC>
void BaseSrvList<HGC>::remove(TypeSrvC *s) {
int i=find_idx(s);
assert(i>=0);
servers->remove_index_fast((unsigned int)i);
if constexpr (std::is_same_v<HGC, MyHGC>) {
myhgc->refresh_online_server_count();
} else if constexpr (std::is_same_v<HGC, PgSQL_HGC>) {
//myhgc->refresh_online_server_count(); FIXME: not implemented
} else {
assert(0);
}
}
template<typename HGC>
BaseSrvList<HGC>::~BaseSrvList() {
myhgc=NULL;
while (servers->len) {
TypeSrvC *mysrvc=(TypeSrvC *)servers->remove_index_fast(0);
delete mysrvc;
}
delete servers;
}

File diff suppressed because it is too large Load Diff

@ -48,6 +48,25 @@ template bool Base_Session<PgSQL_Session, PgSQL_Data_Stream, PgSQL_Backend, PgSQ
template void Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL_Backend, MySQL_Thread>::housekeeping_before_pkts();
template void Base_Session<PgSQL_Session, PgSQL_Data_Stream, PgSQL_Backend, PgSQL_Thread>::housekeeping_before_pkts();
template void Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL_Backend, MySQL_Thread>::update_expired_conns(std::vector<std::function<bool (MySQL_Connection*)>, std::allocator<std::function<bool (MySQL_Connection*)> > > const&);
template void Base_Session<PgSQL_Session, PgSQL_Data_Stream, PgSQL_Backend, PgSQL_Thread>::update_expired_conns(std::vector<std::function<bool (PgSQL_Connection*)>, std::allocator<std::function<bool (PgSQL_Connection*)> > > const&);
template unsigned int Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL_Backend, MySQL_Thread>::NumActiveTransactions(bool);
template unsigned int Base_Session<PgSQL_Session, PgSQL_Data_Stream, PgSQL_Backend, PgSQL_Thread>::NumActiveTransactions(bool);
template void Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL_Backend, MySQL_Thread>::set_unhealthy();
template void Base_Session<PgSQL_Session, PgSQL_Data_Stream, PgSQL_Backend, PgSQL_Thread>::set_unhealthy();
template int Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL_Backend, MySQL_Thread>::FindOneActiveTransaction(bool);
template int Base_Session<PgSQL_Session, PgSQL_Data_Stream, PgSQL_Backend, PgSQL_Thread>::FindOneActiveTransaction(bool);
template bool Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL_Backend, MySQL_Thread>::HasOfflineBackends();
template bool Base_Session<PgSQL_Session, PgSQL_Data_Stream, PgSQL_Backend, PgSQL_Thread>::HasOfflineBackends();
template bool Base_Session<MySQL_Session, MySQL_Data_Stream, MySQL_Backend, MySQL_Thread>::SetEventInOfflineBackends();
template bool Base_Session<PgSQL_Session, PgSQL_Data_Stream, PgSQL_Backend, PgSQL_Thread>::SetEventInOfflineBackends();
template<typename S, typename DS, typename B, typename T>
Base_Session<S,DS,B,T>::Base_Session() {
};
@ -500,3 +519,154 @@ void Base_Session<S,DS,B,T>::housekeeping_before_pkts() {
}
}
}
/**
* @brief Update expired connections based on specified checks.
*
* This function iterates through the list of backends and their connections
* to determine if any connections have expired based on the provided checks.
* If a connection is found to be expired, its hostgroup ID is added to the
* list of expired connections for further processing.
*
* @param checks A vector of function objects representing checks to determine if a connection has expired.
*/
template<typename S, typename DS, typename B, typename T>
using TypeConn = typename std::conditional<
std::is_same_v<S, MySQL_Session>, MySQL_Connection, PgSQL_Connection
>::type;
template<typename S, typename DS, typename B, typename T>
void Base_Session<S,DS,B,T>::update_expired_conns(const vector<function<bool(TypeConn *)>>& checks) {
for (uint32_t i = 0; i < mybes->len; i++) { // iterate through the list of backends
B * mybe = static_cast<B *>(mybes->index(i));
DS * myds = mybe != nullptr ? mybe->server_myds : nullptr;
TypeConn * myconn = myds != nullptr ? myds->myconn : nullptr;
//! it performs a series of checks to determine if it has expired
if (myconn != nullptr) {
const bool is_active_transaction = myconn->IsActiveTransaction();
const bool multiplex_disabled = myconn->MultiplexDisabled(false);
const bool is_idle = myconn->async_state_machine == ASYNC_IDLE;
// Make sure the connection is reusable before performing any check
if (myconn->reusable == true && is_active_transaction == false && multiplex_disabled == false && is_idle) {
for (const function<bool(TypeConn*)>& check : checks) {
if (check(myconn)) {
// If a connection is found to be expired based on the provided checks,
// its hostgroup ID is added to the list of expired connections (hgs_expired_conns)
// for further processing.
this->hgs_expired_conns.push_back(mybe->hostgroup_id);
break;
}
}
}
}
}
}
template<typename S, typename DS, typename B, typename T>
void Base_Session<S,DS,B,T>::set_unhealthy() {
proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Sess:%p\n", this);
healthy=0;
}
template<typename S, typename DS, typename B, typename T>
unsigned int Base_Session<S,DS,B,T>::NumActiveTransactions(bool check_savepoint) {
unsigned int ret=0;
if (mybes==0) return ret;
B *_mybe;
unsigned int i;
for (i=0; i < mybes->len; i++) {
_mybe=(B *)mybes->index(i);
if (_mybe->server_myds) {
if (_mybe->server_myds->myconn) {
if (_mybe->server_myds->myconn->IsActiveTransaction()) {
ret++;
} else {
// we use check_savepoint to check if we shouldn't ignore COMMIT or ROLLBACK due
// to MySQL bug https://bugs.mysql.com/bug.php?id=107875 related to
// SAVEPOINT and autocommit=0
if (check_savepoint) {
if (_mybe->server_myds->myconn->AutocommitFalse_AndSavepoint() == true) {
ret++;
}
}
}
}
}
}
return ret;
}
template<typename S, typename DS, typename B, typename T>
bool Base_Session<S,DS,B,T>::HasOfflineBackends() {
bool ret=false;
if (mybes==0) return ret;
B * _mybe;
unsigned int i;
for (i=0; i < mybes->len; i++) {
_mybe=(B *)mybes->index(i);
if (_mybe->server_myds)
if (_mybe->server_myds->myconn)
if (_mybe->server_myds->myconn->IsServerOffline()) {
ret=true;
return ret;
}
}
return ret;
}
template<typename S, typename DS, typename B, typename T>
bool Base_Session<S,DS,B,T>::SetEventInOfflineBackends() {
bool ret=false;
if (mybes==0) return ret;
B * _mybe;
unsigned int i;
for (i = 0; i < mybes->len; i++) {
_mybe = (B *) mybes->index(i);
if (_mybe->server_myds)
if (_mybe->server_myds->myconn)
if (_mybe->server_myds->myconn->IsServerOffline()) {
_mybe->server_myds->revents |= POLLIN;
ret = true;
}
}
return ret;
}
template<typename S, typename DS, typename B, typename T>
int Base_Session<S,DS,B,T>::FindOneActiveTransaction(bool check_savepoint) {
int ret=-1;
if (mybes==0) return ret;
B * _mybe;
unsigned int i;
for (i=0; i < mybes->len; i++) {
_mybe = (B *) mybes->index(i);
if (_mybe->server_myds) {
if (_mybe->server_myds->myconn) {
if (_mybe->server_myds->myconn->IsKnownActiveTransaction()) {
return (int)_mybe->server_myds->myconn->parent->myhgc->hid;
}
else if (_mybe->server_myds->myconn->IsActiveTransaction()) {
ret = (int)_mybe->server_myds->myconn->parent->myhgc->hid;
}
else {
// we use check_savepoint to check if we shouldn't ignore COMMIT or ROLLBACK due
// to MySQL bug https://bugs.mysql.com/bug.php?id=107875 related to
// SAVEPOINT and autocommit=0
if (check_savepoint) {
if (_mybe->server_myds->myconn->AutocommitFalse_AndSavepoint() == true) {
return (int)_mybe->server_myds->myconn->parent->myhgc->hid;
}
}
}
}
}
}
return ret;
}

@ -138,8 +138,9 @@ default: libproxysql.a
_OBJ_CXX := ProxySQL_GloVars.oo network.oo debug.oo configfile.oo Query_Cache.oo SpookyV2.oo MySQL_Authentication.oo gen_utils.oo sqlite3db.oo mysql_connection.oo MySQL_HostGroups_Manager.oo mysql_data_stream.oo MySQL_Thread.oo MySQL_Session.oo MySQL_Protocol.oo mysql_backend.oo Query_Processor.oo ProxySQL_Admin.oo ProxySQL_Config.oo ProxySQL_Restapi.oo MySQL_Monitor.oo MySQL_Logger.oo thread.oo MySQL_PreparedStatement.oo ProxySQL_Cluster.oo ClickHouse_Authentication.oo ClickHouse_Server.oo ProxySQL_Statistics.oo Chart_bundle_js.oo ProxySQL_HTTP_Server.oo ProxySQL_RESTAPI_Server.oo font-awesome.min.css.oo main-bundle.min.css.oo set_parser.oo MySQL_Variables.oo c_tokenizer.oo proxysql_utils.oo proxysql_coredump.oo proxysql_sslkeylog.oo \
sha256crypt.oo \
BaseSrvList.oo BaseHGC.oo Base_HostGroups_Manager.oo \
QP_rule_text.oo QP_query_digest_stats.oo \
GTID_Server_Data.oo MyHGC.oo MySrvConnList.oo MySrvList.oo MySrvC.oo \
GTID_Server_Data.oo MyHGC.oo MySrvConnList.oo MySrvC.oo \
MySQL_encode.oo MySQL_ResultSet.oo \
ProxySQL_Admin_Tests.oo ProxySQL_Admin_Tests2.oo ProxySQL_Admin_Scheduler.oo ProxySQL_Admin_Disk_Upgrade.oo ProxySQL_Admin_Stats.oo \
Admin_Handler.oo Admin_FlushVariables.oo Admin_Bootstrap.oo \

@ -11,54 +11,6 @@ static unsigned long long array_mysrvc_cands = 0;
extern MySQL_Threads_Handler *GloMTH;
MyHGC::MyHGC(int _hid) {
hid=_hid;
mysrvs=new MySrvList(this);
current_time_now = 0;
new_connections_now = 0;
attributes.initialized = false;
reset_attributes();
// Uninitialized server defaults. Should later be initialized via 'mysql_hostgroup_attributes'.
servers_defaults.weight = -1;
servers_defaults.max_connections = -1;
servers_defaults.use_ssl = -1;
num_online_servers.store(0, std::memory_order_relaxed);;
last_log_time_num_online_servers = 0;
}
void MyHGC::reset_attributes() {
if (attributes.initialized == false) {
attributes.init_connect = NULL;
attributes.comment = NULL;
attributes.ignore_session_variables_text = NULL;
}
attributes.initialized = true;
attributes.configured = false;
attributes.max_num_online_servers = 1000000;
attributes.throttle_connections_per_sec = 1000000;
attributes.autocommit = -1;
attributes.free_connections_pct = 10;
attributes.handle_warnings = -1;
attributes.monitor_slave_lag_when_null = -1;
attributes.multiplex = true;
attributes.connection_warming = false;
free(attributes.init_connect);
attributes.init_connect = NULL;
free(attributes.comment);
attributes.comment = NULL;
free(attributes.ignore_session_variables_text);
attributes.ignore_session_variables_text = NULL;
if (attributes.ignore_session_variables_json) {
delete attributes.ignore_session_variables_json;
attributes.ignore_session_variables_json = NULL;
}
}
MyHGC::~MyHGC() {
reset_attributes(); // free all memory
delete mysrvs;
}
MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_lag_ms, MySQL_Session *sess) {
MySrvC *mysrvc=NULL;
unsigned int j;
@ -400,31 +352,3 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
#endif // TEST_AURORA
return NULL; // if we reach here, we couldn't find any target
}
void MyHGC::refresh_online_server_count() {
if (__sync_fetch_and_add(&glovars.shutdown, 0) != 0)
return;
#ifdef DEBUG
assert(MyHGM->is_locked);
#endif
unsigned int online_servers_count = 0;
for (unsigned int i = 0; i < mysrvs->servers->len; i++) {
MySrvC* mysrvc = (MySrvC*)mysrvs->servers->index(i);
if (mysrvc->get_status() == MYSQL_SERVER_STATUS_ONLINE) {
online_servers_count++;
}
}
num_online_servers.store(online_servers_count, std::memory_order_relaxed);
}
void MyHGC::log_num_online_server_count_error() {
const time_t curtime = time(NULL);
// if this is the first time the method is called or if more than 10 seconds have passed since the last log
if (last_log_time_num_online_servers == 0 ||
((curtime - last_log_time_num_online_servers) > 10)) {
last_log_time_num_online_servers = curtime;
proxy_error(
"Number of online servers detected in a hostgroup exceeds the configured maximum online servers. hostgroup:%u, num_online_servers:%u, max_online_servers:%u\n",
hid, num_online_servers.load(std::memory_order_relaxed), attributes.max_num_online_servers);
}
}

@ -657,17 +657,17 @@ MySQL_HostGroups_Manager::MySQL_HostGroups_Manager() {
status.access_denied_max_user_connections=0;
status.select_for_update_or_equivalent=0;
status.auto_increment_delay_multiplex=0;
#if 0
pthread_mutex_init(&readonly_mutex, NULL);
#endif // 0
pthread_mutex_init(&Group_Replication_Info_mutex, NULL);
pthread_mutex_init(&Galera_Info_mutex, NULL);
pthread_mutex_init(&AWS_Aurora_Info_mutex, NULL);
#ifdef MHM_PTHREAD_MUTEX
#if 0
pthread_mutex_init(&lock, NULL);
#else
spinlock_rwlock_init(&rwlock);
#endif
admindb=NULL; // initialized only if needed
mydb=new SQLite3DB();
#endif // 0
#ifdef DEBUG
mydb->open((char *)"file:mem_mydb?mode=memory&cache=shared", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX);
#else
@ -756,21 +756,7 @@ MySQL_HostGroups_Manager::~MySQL_HostGroups_Manager() {
ev_loop_destroy(gtid_ev_loop);
if (gtid_ev_timer)
free(gtid_ev_timer);
#ifdef MHM_PTHREAD_MUTEX
pthread_mutex_destroy(&lock);
#endif
}
// wrlock() is only required during commit()
void MySQL_HostGroups_Manager::wrlock() {
#ifdef MHM_PTHREAD_MUTEX
pthread_mutex_lock(&lock);
#else
spin_wrlock(&rwlock);
#endif
#ifdef DEBUG
is_locked = true;
#endif
}
void MySQL_HostGroups_Manager::p_update_mysql_error_counter(p_mysql_error_type err_type, unsigned int hid, char* address, uint16_t port, unsigned int code) {
@ -804,18 +790,6 @@ void MySQL_HostGroups_Manager::p_update_mysql_error_counter(p_mysql_error_type e
pthread_mutex_unlock(&mysql_errors_mutex);
}
void MySQL_HostGroups_Manager::wrunlock() {
#ifdef DEBUG
is_locked = false;
#endif
#ifdef MHM_PTHREAD_MUTEX
pthread_mutex_unlock(&lock);
#else
spin_wrunlock(&rwlock);
#endif
}
void MySQL_HostGroups_Manager::wait_servers_table_version(unsigned v, unsigned w) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
@ -917,29 +891,6 @@ int MySQL_HostGroups_Manager::servers_add(SQLite3_result *resultset) {
return 0;
}
/**
* @brief Execute a SQL query and retrieve the resultset.
*
* This function executes a SQL query using the provided query string and returns the resultset obtained from the
* database operation. It also provides an optional error parameter to capture any error messages encountered during
* query execution.
*
* @param query A pointer to a null-terminated string containing the SQL query to be executed.
* @param error A pointer to a char pointer where any error message encountered during query execution will be stored.
* Pass nullptr if error handling is not required.
* @return A pointer to a SQLite3_result object representing the resultset obtained from the query execution. This
* pointer may be nullptr if the query execution fails or returns an empty result.
*/
SQLite3_result * MySQL_HostGroups_Manager::execute_query(char *query, char **error) {
int cols=0;
int affected_rows=0;
SQLite3_result *resultset=NULL;
wrlock();
mydb->execute_statement(query, error , &cols , &affected_rows , &resultset);
wrunlock();
return resultset;
}
/**
* @brief Calculate and update the checksum for a specified table in the database.
*
@ -2279,78 +2230,6 @@ SQLite3_result * MySQL_HostGroups_Manager::dump_table_mysql(const string& name)
return resultset;
}
/**
* @brief Create a new MySQL host group container.
*
* This function creates a new instance of the MySQL host group container (`MyHGC`) with
* the specified host group ID and returns a pointer to it.
*
* @param _hid The host group ID for the new container.
* @return A pointer to the newly created `MyHGC` instance.
*/
MyHGC * MySQL_HostGroups_Manager::MyHGC_create(unsigned int _hid) {
MyHGC *myhgc=new MyHGC(_hid);
return myhgc;
}
/**
* @brief Find a MySQL host group container by host group ID.
*
* This function searches for a MySQL host group container with the specified host group ID
* in the list of host groups. If found, it returns a pointer to the container; otherwise,
* it returns a null pointer.
*
* @param _hid The host group ID to search for.
* @return A pointer to the found `MyHGC` instance if found; otherwise, a null pointer.
*/
MyHGC * MySQL_HostGroups_Manager::MyHGC_find(unsigned int _hid) {
if (MyHostGroups->len < 100) {
// for few HGs, we use the legacy search
for (unsigned int i=0; i<MyHostGroups->len; i++) {
MyHGC *myhgc=(MyHGC *)MyHostGroups->index(i);
if (myhgc->hid==_hid) {
return myhgc;
}
}
} else {
// for a large number of HGs, we use the unordered_map
// this search is slower for a small number of HGs, therefore we use
// it only for large number of HGs
std::unordered_map<unsigned int, MyHGC *>::const_iterator it = MyHostGroups_map.find(_hid);
if (it != MyHostGroups_map.end()) {
MyHGC *myhgc = it->second;
return myhgc;
}
}
return NULL;
}
/**
* @brief Lookup or create a MySQL host group container by host group ID.
*
* This function looks up a MySQL host group container with the specified host group ID. If
* found, it returns a pointer to the existing container; otherwise, it creates a new container
* with the specified host group ID, adds it to the list of host groups, and returns a pointer
* to it.
*
* @param _hid The host group ID to lookup or create.
* @return A pointer to the found or newly created `MyHGC` instance.
* @note The function assertion fails if a newly created container is not found.
*/
MyHGC * MySQL_HostGroups_Manager::MyHGC_lookup(unsigned int _hid) {
MyHGC *myhgc=NULL;
myhgc=MyHGC_find(_hid);
if (myhgc==NULL) {
myhgc=MyHGC_create(_hid);
} else {
return myhgc;
}
assert(myhgc);
MyHostGroups->add(myhgc);
MyHostGroups_map.emplace(_hid,myhgc);
return myhgc;
}
void MySQL_HostGroups_Manager::increase_reset_counter() {
wrlock();
status.myconnpoll_reset++;

@ -783,45 +783,6 @@ MySQL_Session::~MySQL_Session() {
}
}
/**
* @brief Update expired connections based on specified checks.
*
* This function iterates through the list of backends and their connections
* to determine if any connections have expired based on the provided checks.
* If a connection is found to be expired, its hostgroup ID is added to the
* list of expired connections for further processing.
*
* @param checks A vector of function objects representing checks to determine if a connection has expired.
*/
void MySQL_Session::update_expired_conns(const vector<function<bool(MySQL_Connection*)>>& checks) {
for (uint32_t i = 0; i < mybes->len; i++) { // iterate through the list of backends
MySQL_Backend* mybe = static_cast<MySQL_Backend*>(mybes->index(i));
MySQL_Data_Stream* myds = mybe != nullptr ? mybe->server_myds : nullptr;
MySQL_Connection* myconn = myds != nullptr ? myds->myconn : nullptr;
//! it performs a series of checks to determine if it has expired
if (myconn != nullptr) {
const bool is_active_transaction = myconn->IsActiveTransaction();
const bool multiplex_disabled = myconn->MultiplexDisabled(false);
const bool is_idle = myconn->async_state_machine == ASYNC_IDLE;
// Make sure the connection is reusable before performing any check
if (myconn->reusable==true && is_active_transaction==false && multiplex_disabled==false && is_idle) {
for (const function<bool(MySQL_Connection*)>& check : checks) {
if (check(myconn)) {
// If a connection is found to be expired based on the provided checks,
// its hostgroup ID is added to the list of expired connections (hgs_expired_conns)
// for further processing.
this->hgs_expired_conns.push_back(mybe->hostgroup_id);
break;
}
}
}
}
}
}
/**
* @brief Handles COMMIT or ROLLBACK commands received from the client.
*
@ -5861,84 +5822,6 @@ void MySQL_Session::handler_WCD_SS_MCQ_qpo_LargePacket(PtrSize_t *pkt) {
l_free(pkt->size,pkt->ptr);
}
/*
// this function as inline in handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo
// returned values:
// 0 : no action
// 1 : return false
// 2 : return true
int MySQL_Session::handler_WCD_SS_MCQ_qpo_Parse_SQL_LOG_BIN(PtrSize_t *pkt, bool *lock_hostgroup, unsigned int nTrx, string& nq) {
re2::RE2::Options *opt2=new re2::RE2::Options(RE2::Quiet);
opt2->set_case_sensitive(false);
char *pattern=(char *)"(?: *)SET *(?:|SESSION +|@@|@@session.)SQL_LOG_BIN *(?:|:)= *(\\d+) *(?:(|;|-- .*|#.*))$";
re2::RE2 *re=new RE2(pattern, *opt2);
int i;
int rc=RE2::PartialMatch(nq, *re, &i);
delete re;
delete opt2;
if (rc && ( i==0 || i==1) ) {
//fprintf(stderr,"sql_log_bin=%d\n", i);
if (i == 1) {
if (!mysql_variables.client_set_value(this, SQL_SQL_LOG_BIN, "1"))
return 1;
}
else if (i == 0) {
if (!mysql_variables.client_set_value(this, SQL_SQL_LOG_BIN, "0"))
return 1;
}
#ifdef DEBUG
proxy_info("Setting SQL_LOG_BIN to %d\n", i);
#endif
#ifdef DEBUG
{
string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength);
proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Setting SQL_LOG_BIN to %d for query: %s\n", i, nqn.c_str());
}
#endif
// we recompute command_type instead of taking it from the calling function
unsigned char command_type=*((unsigned char *)pkt->ptr+sizeof(mysql_hdr));
if (command_type == _MYSQL_COM_QUERY) {
client_myds->DSS=STATE_QUERY_SENT_NET;
uint16_t setStatus = (nTrx ? SERVER_STATUS_IN_TRANS : 0 );
if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT;
client_myds->myprot.generate_pkt_OK(true,NULL,NULL,1,0,0,setStatus,0,NULL);
client_myds->DSS=STATE_SLEEP;
status=WAITING_CLIENT_DATA;
RequestEnd(NULL);
l_free(pkt->size,pkt->ptr);
return 2;
}
} else {
int kq = 0;
kq = strncmp((const char *)CurrentQuery.QueryPointer, (const char *)"SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;" , CurrentQuery.QueryLength);
#ifdef DEBUG
{
string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength);
proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Setting SQL_LOG_BIN to %d for query: %s\n", i, nqn.c_str());
}
#endif
if (kq == 0) {
client_myds->DSS=STATE_QUERY_SENT_NET;
uint16_t setStatus = (nTrx ? SERVER_STATUS_IN_TRANS : 0 );
if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT;
client_myds->myprot.generate_pkt_OK(true,NULL,NULL,1,0,0,setStatus,0,NULL);
client_myds->DSS=STATE_SLEEP;
status=WAITING_CLIENT_DATA;
RequestEnd(NULL);
l_free(pkt->size,pkt->ptr);
return 2;
} else {
string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength);
proxy_error("Unable to parse query. If correct, report it as a bug: %s\n", nqn.c_str());
unable_to_parse_set_statement(lock_hostgroup);
return 1;
}
}
return 0;
}
*/
bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo(PtrSize_t *pkt, bool *lock_hostgroup, ps_type prepare_stmt_type) {
/*
lock_hostgroup:
@ -6072,15 +5955,6 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C
RE2::GlobalReplace(&nq,(char *)"(?U)/\\*.*\\*/",(char *)"");
// remove trailing space and semicolon if present. See issue#4380
nq.erase(nq.find_last_not_of(" ;") + 1);
/*
// we do not threat SET SQL_LOG_BIN as a special case
if (match_regexes && match_regexes[0]->match(dig)) {
int rc = handler_WCD_SS_MCQ_qpo_Parse_SQL_LOG_BIN(pkt, lock_hostgroup, nTrx, nq);
if (rc == 1) return false;
if (rc == 2) return true;
// if rc == 0 , continue as normal
}
*/
if (
(
match_regexes && (match_regexes[1]->match(dig))
@ -7481,102 +7355,6 @@ void MySQL_Session::SQLite3_to_MySQL(SQLite3_result *result, char *error, int af
}
}
void MySQL_Session::set_unhealthy() {
proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Sess:%p\n", this);
healthy=0;
}
unsigned int MySQL_Session::NumActiveTransactions(bool check_savepoint) {
unsigned int ret=0;
if (mybes==0) return ret;
MySQL_Backend *_mybe;
unsigned int i;
for (i=0; i < mybes->len; i++) {
_mybe=(MySQL_Backend *)mybes->index(i);
if (_mybe->server_myds) {
if (_mybe->server_myds->myconn) {
if (_mybe->server_myds->myconn->IsActiveTransaction()) {
ret++;
} else {
// we use check_savepoint to check if we shouldn't ignore COMMIT or ROLLBACK due
// to MySQL bug https://bugs.mysql.com/bug.php?id=107875 related to
// SAVEPOINT and autocommit=0
if (check_savepoint) {
if (_mybe->server_myds->myconn->AutocommitFalse_AndSavepoint() == true) {
ret++;
}
}
}
}
}
}
return ret;
}
bool MySQL_Session::HasOfflineBackends() {
bool ret=false;
if (mybes==0) return ret;
MySQL_Backend *_mybe;
unsigned int i;
for (i=0; i < mybes->len; i++) {
_mybe=(MySQL_Backend *)mybes->index(i);
if (_mybe->server_myds)
if (_mybe->server_myds->myconn)
if (_mybe->server_myds->myconn->IsServerOffline()) {
ret=true;
return ret;
}
}
return ret;
}
bool MySQL_Session::SetEventInOfflineBackends() {
bool ret=false;
if (mybes==0) return ret;
MySQL_Backend *_mybe;
unsigned int i;
for (i=0; i < mybes->len; i++) {
_mybe=(MySQL_Backend *)mybes->index(i);
if (_mybe->server_myds)
if (_mybe->server_myds->myconn)
if (_mybe->server_myds->myconn->IsServerOffline()) {
_mybe->server_myds->revents|=POLLIN;
ret = true;
}
}
return ret;
}
int MySQL_Session::FindOneActiveTransaction(bool check_savepoint) {
int ret=-1;
if (mybes==0) return ret;
MySQL_Backend *_mybe;
unsigned int i;
for (i=0; i < mybes->len; i++) {
_mybe=(MySQL_Backend *)mybes->index(i);
if (_mybe->server_myds) {
if (_mybe->server_myds->myconn) {
if (_mybe->server_myds->myconn->IsKnownActiveTransaction()) {
return (int)_mybe->server_myds->myconn->parent->myhgc->hid;
} else if (_mybe->server_myds->myconn->IsActiveTransaction()) {
ret = (int)_mybe->server_myds->myconn->parent->myhgc->hid;
} else {
// we use check_savepoint to check if we shouldn't ignore COMMIT or ROLLBACK due
// to MySQL bug https://bugs.mysql.com/bug.php?id=107875 related to
// SAVEPOINT and autocommit=0
if (check_savepoint) {
if (_mybe->server_myds->myconn->AutocommitFalse_AndSavepoint() == true) {
return (int)_mybe->server_myds->myconn->parent->myhgc->hid;
}
}
}
}
}
}
return ret;
}
unsigned long long MySQL_Session::IdleTime() {
unsigned long long ret = 0;
if (client_myds==0) return 0;
@ -7592,7 +7370,6 @@ unsigned long long MySQL_Session::IdleTime() {
}
// this is called either from RequestEnd(), or at the end of executing
// prepared statements
void MySQL_Session::LogQuery(MySQL_Data_Stream *myds) {

@ -1,46 +0,0 @@
#include "MySQL_HostGroups_Manager.h"
class MySrvConnList;
class MySrvC;
class MySrvList;
class MyHGC;
MySrvList::MySrvList(MyHGC *_myhgc) {
myhgc=_myhgc;
servers=new PtrArray();
}
void MySrvList::add(MySrvC *s) {
if (s->myhgc==NULL) {
s->myhgc=myhgc;
}
servers->add(s);
myhgc->refresh_online_server_count();
}
int MySrvList::find_idx(MySrvC *s) {
for (unsigned int i=0; i<servers->len; i++) {
MySrvC *mysrv=(MySrvC *)servers->index(i);
if (mysrv==s) {
return (unsigned int)i;
}
}
return -1;
}
void MySrvList::remove(MySrvC *s) {
int i=find_idx(s);
assert(i>=0);
servers->remove_index_fast((unsigned int)i);
myhgc->refresh_online_server_count();
}
MySrvList::~MySrvList() {
myhgc=NULL;
while (servers->len) {
MySrvC *mysrvc=(MySrvC *)servers->remove_index_fast(0);
delete mysrvc;
}
delete servers;
}

File diff suppressed because it is too large Load Diff

@ -708,30 +708,6 @@ PgSQL_Session::~PgSQL_Session() {
}
}
void PgSQL_Session::update_expired_conns(const vector<function<bool(PgSQL_Connection*)>>& checks) {
for (uint32_t i = 0; i < mybes->len; i++) {
PgSQL_Backend* mybe = static_cast<PgSQL_Backend*>(mybes->index(i));
PgSQL_Data_Stream* myds = mybe != nullptr ? mybe->server_myds : nullptr;
PgSQL_Connection* myconn = myds != nullptr ? myds->myconn : nullptr;
if (myconn != nullptr) {
const bool is_active_transaction = myconn->IsActiveTransaction();
const bool multiplex_disabled = myconn->MultiplexDisabled(false);
const bool is_idle = myconn->async_state_machine == ASYNC_IDLE;
// Make sure the connection is reusable before performing any check
if (myconn->reusable == true && is_active_transaction == false && multiplex_disabled == false && is_idle) {
for (const function<bool(PgSQL_Connection*)>& check : checks) {
if (check(myconn)) {
this->hgs_expired_conns.push_back(mybe->hostgroup_id);
break;
}
}
}
}
}
}
bool PgSQL_Session::handler_CommitRollback(PtrSize_t* pkt) {
if (pkt->size <= 5) { return false; }
char c = ((char*)pkt->ptr)[5];
@ -5565,84 +5541,6 @@ void PgSQL_Session::handler_WCD_SS_MCQ_qpo_LargePacket(PtrSize_t* pkt) {
l_free(pkt->size, pkt->ptr);
}
/*
// this function as inline in handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo
// returned values:
// 0 : no action
// 1 : return false
// 2 : return true
int PgSQL_Session::handler_WCD_SS_MCQ_qpo_Parse_SQL_LOG_BIN(PtrSize_t *pkt, bool *lock_hostgroup, unsigned int nTrx, string& nq) {
re2::RE2::Options *opt2=new re2::RE2::Options(RE2::Quiet);
opt2->set_case_sensitive(false);
char *pattern=(char *)"(?: *)SET *(?:|SESSION +|@@|@@session.)SQL_LOG_BIN *(?:|:)= *(\\d+) *(?:(|;|-- .*|#.*))$";
re2::RE2 *re=new RE2(pattern, *opt2);
int i;
int rc=RE2::PartialMatch(nq, *re, &i);
delete re;
delete opt2;
if (rc && ( i==0 || i==1) ) {
//fprintf(stderr,"sql_log_bin=%d\n", i);
if (i == 1) {
if (!pgsql_variables.client_set_value(this, SQL_SQL_LOG_BIN, "1"))
return 1;
}
else if (i == 0) {
if (!pgsql_variables.client_set_value(this, SQL_SQL_LOG_BIN, "0"))
return 1;
}
#ifdef DEBUG
proxy_info("Setting SQL_LOG_BIN to %d\n", i);
#endif
#ifdef DEBUG
{
string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength);
proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Setting SQL_LOG_BIN to %d for query: %s\n", i, nqn.c_str());
}
#endif
// we recompute command_type instead of taking it from the calling function
unsigned char command_type=*((unsigned char *)pkt->ptr+sizeof(mysql_hdr));
if (command_type == _MYSQL_COM_QUERY) {
client_myds->DSS=STATE_QUERY_SENT_NET;
uint16_t setStatus = (nTrx ? SERVER_STATUS_IN_TRANS : 0 );
if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT;
client_myds->myprot.generate_pkt_OK(true,NULL,NULL,1,0,0,setStatus,0,NULL);
client_myds->DSS=STATE_SLEEP;
status=WAITING_CLIENT_DATA;
RequestEnd(NULL);
l_free(pkt->size,pkt->ptr);
return 2;
}
} else {
int kq = 0;
kq = strncmp((const char *)CurrentQuery.QueryPointer, (const char *)"SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;" , CurrentQuery.QueryLength);
#ifdef DEBUG
{
string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength);
proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Setting SQL_LOG_BIN to %d for query: %s\n", i, nqn.c_str());
}
#endif
if (kq == 0) {
client_myds->DSS=STATE_QUERY_SENT_NET;
uint16_t setStatus = (nTrx ? SERVER_STATUS_IN_TRANS : 0 );
if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT;
client_myds->myprot.generate_pkt_OK(true,NULL,NULL,1,0,0,setStatus,0,NULL);
client_myds->DSS=STATE_SLEEP;
status=WAITING_CLIENT_DATA;
RequestEnd(NULL);
l_free(pkt->size,pkt->ptr);
return 2;
} else {
string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength);
proxy_error("Unable to parse query. If correct, report it as a bug: %s\n", nqn.c_str());
unable_to_parse_set_statement(lock_hostgroup);
return 1;
}
}
return 0;
}
*/
bool PgSQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo(PtrSize_t* pkt, bool* lock_hostgroup, PgSQL_ps_type prepare_stmt_type) {
/*
lock_hostgroup:
@ -5777,15 +5675,6 @@ bool PgSQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C
RE2::GlobalReplace(&nq, (char*)"(?U)/\\*.*\\*/", (char*)"");
// remove trailing space and semicolon if present. See issue#4380
nq.erase(nq.find_last_not_of(" ;") + 1);
/*
// we do not threat SET SQL_LOG_BIN as a special case
if (match_regexes && match_regexes[0]->match(dig)) {
int rc = handler_WCD_SS_MCQ_qpo_Parse_SQL_LOG_BIN(pkt, lock_hostgroup, nTrx, nq);
if (rc == 1) return false;
if (rc == 2) return true;
// if rc == 0 , continue as normal
}
*/
if (
(
match_regexes && (match_regexes[1]->match(dig))
@ -7283,105 +7172,6 @@ void PgSQL_Session::SQLite3_to_MySQL(SQLite3_result* result, char* error, int af
}
}
void PgSQL_Session::set_unhealthy() {
proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Sess:%p\n", this);
healthy = 0;
}
unsigned int PgSQL_Session::NumActiveTransactions(bool check_savepoint) {
unsigned int ret = 0;
if (mybes == 0) return ret;
PgSQL_Backend* _mybe;
unsigned int i;
for (i = 0; i < mybes->len; i++) {
_mybe = (PgSQL_Backend*)mybes->index(i);
if (_mybe->server_myds) {
if (_mybe->server_myds->myconn) {
if (_mybe->server_myds->myconn->IsActiveTransaction()) {
ret++;
}
else {
// we use check_savepoint to check if we shouldn't ignore COMMIT or ROLLBACK due
// to MySQL bug https://bugs.pgsql.com/bug.php?id=107875 related to
// SAVEPOINT and autocommit=0
if (check_savepoint) {
if (_mybe->server_myds->myconn->AutocommitFalse_AndSavepoint() == true) {
ret++;
}
}
}
}
}
}
return ret;
}
bool PgSQL_Session::HasOfflineBackends() {
bool ret = false;
if (mybes == 0) return ret;
PgSQL_Backend* _mybe;
unsigned int i;
for (i = 0; i < mybes->len; i++) {
_mybe = (PgSQL_Backend*)mybes->index(i);
if (_mybe->server_myds)
if (_mybe->server_myds->myconn)
if (_mybe->server_myds->myconn->IsServerOffline()) {
ret = true;
return ret;
}
}
return ret;
}
bool PgSQL_Session::SetEventInOfflineBackends() {
bool ret = false;
if (mybes == 0) return ret;
PgSQL_Backend* _mybe;
unsigned int i;
for (i = 0; i < mybes->len; i++) {
_mybe = (PgSQL_Backend*)mybes->index(i);
if (_mybe->server_myds)
if (_mybe->server_myds->myconn)
if (_mybe->server_myds->myconn->IsServerOffline()) {
_mybe->server_myds->revents |= POLLIN;
ret = true;
}
}
return ret;
}
int PgSQL_Session::FindOneActiveTransaction(bool check_savepoint) {
int ret = -1;
if (mybes == 0) return ret;
PgSQL_Backend* _mybe;
unsigned int i;
for (i = 0; i < mybes->len; i++) {
_mybe = (PgSQL_Backend*)mybes->index(i);
if (_mybe->server_myds) {
if (_mybe->server_myds->myconn) {
if (_mybe->server_myds->myconn->IsKnownActiveTransaction()) {
return (int)_mybe->server_myds->myconn->parent->myhgc->hid;
}
else if (_mybe->server_myds->myconn->IsActiveTransaction()) {
ret = (int)_mybe->server_myds->myconn->parent->myhgc->hid;
}
else {
// we use check_savepoint to check if we shouldn't ignore COMMIT or ROLLBACK due
// to MySQL bug https://bugs.pgsql.com/bug.php?id=107875 related to
// SAVEPOINT and autocommit=0
if (check_savepoint) {
if (_mybe->server_myds->myconn->AutocommitFalse_AndSavepoint() == true) {
return (int)_mybe->server_myds->myconn->parent->myhgc->hid;
}
}
}
}
}
}
return ret;
}
unsigned long long PgSQL_Session::IdleTime() {
unsigned long long ret = 0;
if (client_myds == 0) return 0;

@ -5193,17 +5193,17 @@ PgSQL_Connection* PgSQL_Thread::get_MyConn_local(unsigned int _hid, PgSQL_Sessio
if (it != parents.end()) {
// we didn't exclude this server (yet?)
bool gtid_found = false;
#if 0
gtid_found = PgHGM->gtid_exists(mysrvc, gtid_uuid, gtid_trxid);
#endif // 0
if (gtid_found) { // this server has the correct GTID
c = (PgSQL_Connection*)cached_connections->remove_index_fast(i);
return c;
}
else {
} else {
parents.push_back(mysrvc); // stop evaluating this server
}
}
}
else { // gtid_is not used
} else { // gtid_is not used
if (max_lag_ms >= 0) {
if ((unsigned int)max_lag_ms < (c->parent->aws_aurora_current_lag_us / 1000)) {
status_variables.stvar[st_var_aws_aurora_replicas_skipped_during_query]++;

@ -79,6 +79,7 @@ int main() {
{ 1 , "show VARIABLES" },
{ 1 , "show ALL variables" },
{ 1 , "show MYSQL variables" },
{ 1 , "SHOW PGSQL VARIABLES" },
{ 1 , "SHOW admin VARIABLES" },
{ 3 , "sHoW DATABASES" },
{ 3 , "sHoW SCHEMAS" },

Loading…
Cancel
Save