diff --git a/include/MySQL_Session.h b/include/MySQL_Session.h index ecd2f8ffd..1569887dd 100644 --- a/include/MySQL_Session.h +++ b/include/MySQL_Session.h @@ -6,6 +6,8 @@ #include "../deps/json/json.hpp" using json = nlohmann::json; +class MySQL_Variables; + enum proxysql_session_type { PROXYSQL_SESSION_MYSQL, PROXYSQL_SESSION_ADMIN, @@ -70,7 +72,6 @@ class MySQL_Session { private: int handler_ret; - std::stack previous_status; void handler___status_CONNECTING_CLIENT___STATE_SERVER_HANDSHAKE(PtrSize_t *, bool *); void handler___status_CHANGING_USER_CLIENT___STATE_CLIENT_HANDSHAKE(PtrSize_t *, bool *); @@ -106,13 +107,13 @@ class MySQL_Session int handler_again___status_RESETTING_CONNECTION(); void handler_again___new_thread_to_kill_connection(); + bool handler_again___verify_backend(int var); bool handler_again___verify_backend_charset(); bool handler_again___verify_init_connect(); bool handler_again___verify_ldap_user_variable(); bool handler_again___verify_backend_autocommit(); bool handler_again___verify_backend_user_schema(); bool handler_again___verify_backend_sql_log_bin(); - bool handler_again___verify_backend_sql_mode(); bool handler_again___verify_backend_time_zone(); bool handler_again___verify_backend_isolation_level(); bool handler_again___verify_backend_transaction_read(); @@ -120,8 +121,6 @@ class MySQL_Session bool handler_again___verify_backend_character_set_results(); bool handler_again___verify_backend_session_track_gtids(); bool handler_again___verify_backend_sql_auto_is_null(); - bool handler_again___verify_backend_sql_select_limit(); - bool handler_again___verify_backend_sql_safe_updates(); bool handler_again___verify_backend_collation_connection(); bool handler_again___verify_backend_net_write_timeout(); bool handler_again___verify_backend_max_join_size(); @@ -145,7 +144,6 @@ class MySQL_Session bool handler_again___status_SETTING_COLLATION_CONNECTION(int *); bool handler_again___status_SETTING_NET_WRITE_TIMEOUT(int *); bool handler_again___status_SETTING_MAX_JOIN_SIZE(int *); - bool handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, char *var_name, char *var_value, bool no_quote=false, bool set_transaction=false); bool handler_again___status_CHANGING_SCHEMA(int *); bool handler_again___status_CONNECTING_SERVER(int *); bool handler_again___status_CHANGING_USER_SERVER(int *); @@ -157,6 +155,8 @@ class MySQL_Session 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); + std::stack previous_status; void * operator new(size_t); void operator delete(void *); @@ -178,6 +178,7 @@ class MySQL_Session MySQL_Data_Stream *client_myds; MySQL_Data_Stream *server_myds; char * default_schema; + std::unique_ptr mysql_variables; //this pointer is always initialized inside handler(). // it is an attempt to start simplifying the complexing of handler() diff --git a/include/MySQL_Variables.h b/include/MySQL_Variables.h new file mode 100644 index 000000000..17f7b8d50 --- /dev/null +++ b/include/MySQL_Variables.h @@ -0,0 +1,52 @@ +#ifndef MYSQL_VARIABLES_H +#define MYSQL_VARIABLES_H + +#include "proxysql.h" +#include "cpp.h" + +#include +#include +#include + +class MySQL_Session; + +class Updater { +public: + virtual bool verify_variables(MySQL_Session* session, int idx) = 0; + virtual bool update_server_variable(MySQL_Session* session, int idx, int &_rc) = 0; +}; + +class Generic_Updater : public Updater { +public: + bool verify_variables(MySQL_Session* session, int idx); + bool update_server_variable(MySQL_Session* session, int idx, int &_rc); +}; + +class MySQL_Variables { + MySQL_Session* session; +public: + bool verify_generic_variable(uint32_t *be_int, char **be_var, char *def, uint32_t *fe_int, char *fe_var, enum session_status next_sess_status); + static int session_by_var[SQL_NAME_LAST]; + static int var_by_session[NONE]; + static bool quotes[SQL_NAME_LAST]; + static bool set_transaction[SQL_NAME_LAST]; + Updater* updaters[SQL_NAME_LAST]; + + MySQL_Variables(MySQL_Session* session); + virtual ~MySQL_Variables(); + + void client_set_value(int idx, const char* value); + const char* client_get_value(int idx); + uint32_t client_get_hash(int idx); + + void server_set_value(int idx, const char* value); + const char* server_get_value(int idx); + uint32_t server_get_hash(int idx); + + bool verify_variable(int idx); + bool update_variable(int &_rc); + +}; + +#endif // #ifndef MYSQL_VARIABLES_H + diff --git a/include/mysql_connection.h b/include/mysql_connection.h index 140e533b0..cc2133f95 100644 --- a/include/mysql_connection.h +++ b/include/mysql_connection.h @@ -4,6 +4,9 @@ #include "proxysql.h" #include "cpp.h" +#include "../deps/json/json.hpp" +using json = nlohmann::json; + #define STATUS_MYSQL_CONNECTION_TRANSACTION 0x00000001 #define STATUS_MYSQL_CONNECTION_COMPRESSION 0x00000002 #define STATUS_MYSQL_CONNECTION_USER_VARIABLE 0x00000004 @@ -16,6 +19,16 @@ #define STATUS_MYSQL_CONNECTION_FOUND_ROWS 0x00000200 #define STATUS_MYSQL_CONNECTION_NO_BACKSLASH_ESCAPES 0x00000400 +class Variable { +public: + char *value; + uint32_t hash; + void fill_server_internal_session(json &j, int conn_num, int idx); + void fill_client_internal_session(json &j, int idx); + static const char set_name[SQL_NAME_LAST][64]; + static const char proxysql_internal_session_name[SQL_NAME_LAST][64]; +}; + enum charset_action { UNKNOWN, NAMES, @@ -46,18 +59,6 @@ class MySQL_Connection { public: struct { char *server_version; - char *sql_mode; - char *time_zone; - uint32_t sql_mode_int; - uint32_t time_zone_int; - uint32_t character_set_results_int; - uint32_t isolation_level_int; - uint32_t transaction_read_int; - uint32_t tx_isolation_int; - uint32_t session_track_gtids_int; - uint32_t sql_auto_is_null_int; - uint32_t sql_select_limit_int; - uint32_t sql_safe_updates_int; uint32_t collation_connection_int; uint32_t net_write_timeout_int; uint32_t max_join_size_int; @@ -67,29 +68,12 @@ class MySQL_Connection { unsigned int compression_min_length; char *init_connect; bool init_connect_sent; - char * character_set_results; - char * isolation_level; - char * transaction_read; - char * tx_isolation; - char * session_track_gtids; - char * sql_auto_is_null; - char * sql_select_limit; - char * sql_safe_updates; char * collation_connection; char * net_write_timeout; char * max_join_size; - bool isolation_level_sent; - bool tx_isolation_sent; - bool transaction_read_sent; - bool character_set_results_sent; - bool session_track_gtids_sent; - bool sql_auto_is_null_sent; - bool sql_select_limit_sent; - bool sql_safe_updates_sent; bool collation_connection_sent; bool net_write_timeout_sent; bool max_join_size_sent; - bool sql_mode_sent; char *ldap_user_variable; char *ldap_user_variable_value; bool ldap_user_variable_sent; @@ -101,6 +85,7 @@ class MySQL_Connection { bool autocommit; bool no_backslash_escapes; } options; + Variable variables[SQL_NAME_LAST]; struct { unsigned long length; char *ptr; diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h index efa51eed3..2152da008 100644 --- a/include/proxysql_structs.h +++ b/include/proxysql_structs.h @@ -146,6 +146,22 @@ enum MySQL_DS_type { }; +enum variable_name { + SQL_SAFE_UPDATES, + SQL_SELECT_LIMIT, + SQL_SQL_MODE, + SQL_TIME_ZONE, + SQL_CHARACTER_SET_RESULTS, + SQL_ISOLATION_LEVEL, + SQL_TRANSACTION_READ, + SQL_SESSION_TRACK_GTIDS, + SQL_SQL_AUTO_IS_NULL, +/* SQL_COLLATION_CONNECTION, + SQL_NET_WRITE_TIMEOUT, + SQL_MAX_JOIN_SIZE,*/ + SQL_NAME_LAST +}; + enum session_status { CONNECTING_CLIENT, CONNECTING_SERVER, @@ -168,7 +184,6 @@ enum session_status { SETTING_TIME_ZONE, SETTING_ISOLATION_LEVEL, SETTING_TRANSACTION_READ, - SETTING_TX_ISOLATION, SETTING_CHARACTER_SET_RESULTS, SETTING_SESSION_TRACK_GTIDS, SETTING_SQL_AUTO_IS_NULL, diff --git a/lib/Makefile b/lib/Makefile index 6aef3a705..ba33b8359 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -95,7 +95,7 @@ default: libproxysql.a _OBJ = c_tokenizer.o OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ)) -_OBJ_CXX = ProxySQL_GloVars.oo network.oo debug.oo configfile.oo Query_Cache.oo SpookyV2.oo MySQL_Authentication.oo gen_utils.oo sqlite3db.oo mysql_connection.oo MySQL_HostGroups_Manager.oo mysql_data_stream.oo MySQL_Thread.oo MySQL_Session.oo MySQL_Protocol.oo mysql_backend.oo Query_Processor.oo ProxySQL_Admin.oo 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 +_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 OBJ_CXX = $(patsubst %,$(ODIR)/%,$(_OBJ_CXX)) HEADERS = ../include/*.h ../include/*.hpp diff --git a/lib/MySQL_HostGroups_Manager.cpp b/lib/MySQL_HostGroups_Manager.cpp index 38c4fcb62..46228d129 100644 --- a/lib/MySQL_HostGroups_Manager.cpp +++ b/lib/MySQL_HostGroups_Manager.cpp @@ -3082,12 +3082,12 @@ SQLite3_result * MySQL_HostGroups_Manager::SQL3_Free_Connections() { pta[6] = strdup(conn->options.init_connect); } pta[7] = NULL; - if (conn->options.time_zone) { - pta[7] = strdup(conn->options.time_zone); + if (conn->variables[SQL_TIME_ZONE].value) { + pta[7] = strdup(conn->variables[SQL_TIME_ZONE].value); } pta[8] = NULL; - if (conn->options.sql_mode) { - pta[8] = strdup(conn->options.sql_mode); + if (conn->variables[SQL_SQL_MODE].value) { + pta[8] = strdup(conn->variables[SQL_SQL_MODE].value); } sprintf(buf,"%d", conn->options.autocommit); pta[9]=strdup(buf); diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 442697927..fdb8e7a1b 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -14,6 +14,7 @@ #include "MySQL_LDAP_Authentication.hpp" #include "MySQL_Protocol.h" #include "SQLite3_Server.h" +#include "MySQL_Variables.h" #include "libinjection.h" @@ -495,6 +496,7 @@ void MySQL_Session::init() { mybes= new PtrArray(4); sess_STMTs_meta=new MySQL_STMTs_meta(); SLDH=new StmtLongDataHandler(); + mysql_variables = std::unique_ptr(new MySQL_Variables(this)); } void MySQL_Session::reset() { @@ -957,16 +959,9 @@ void MySQL_Session::generate_proxysql_internal_session_json(json &j) { j["client"]["DSS"] = client_myds->DSS; j["default_schema"] = ( default_schema ? default_schema : "" ); j["transaction_persistent"] = transaction_persistent; - j["conn"]["sql_mode"] = ( client_myds->myconn->options.sql_mode ? client_myds->myconn->options.sql_mode : "") ; - j["conn"]["time_zone"] = ( client_myds->myconn->options.time_zone ? client_myds->myconn->options.time_zone : "") ; - j["conn"]["isolation_level"] = ( client_myds->myconn->options.isolation_level ? client_myds->myconn->options.isolation_level : "") ; - j["conn"]["transaction_read"] = ( client_myds->myconn->options.transaction_read ? client_myds->myconn->options.transaction_read : "") ; - j["conn"]["tx_isolation"] = ( client_myds->myconn->options.tx_isolation ? client_myds->myconn->options.tx_isolation : "") ; - j["conn"]["character_set_results"] = ( client_myds->myconn->options.character_set_results ? client_myds->myconn->options.character_set_results : "") ; - j["conn"]["session_track_gtids"] = ( client_myds->myconn->options.session_track_gtids ? client_myds->myconn->options.session_track_gtids : "") ; - j["conn"]["sql_auto_is_null"] = ( client_myds->myconn->options.sql_auto_is_null ? client_myds->myconn->options.sql_auto_is_null : "") ; - j["conn"]["sql_select_limit"] = ( client_myds->myconn->options.sql_select_limit ? client_myds->myconn->options.sql_select_limit : "") ; - j["conn"]["sql_safe_updates"] = ( client_myds->myconn->options.sql_safe_updates ? client_myds->myconn->options.sql_safe_updates : "") ; + for (auto idx = 0; idx < SQL_NAME_LAST; idx++) { + client_myds->myconn->variables[idx].fill_client_internal_session(j, idx); + } j["conn"]["collation_connection"] = ( client_myds->myconn->options.collation_connection ? client_myds->myconn->options.collation_connection : "") ; j["conn"]["net_write_timeout"] = ( client_myds->myconn->options.net_write_timeout ? client_myds->myconn->options.net_write_timeout : "") ; j["conn"]["max_join_size"] = ( client_myds->myconn->options.max_join_size ? client_myds->myconn->options.max_join_size : "") ; @@ -1003,6 +998,9 @@ void MySQL_Session::generate_proxysql_internal_session_json(json &j) { j["backends"][i]["stream"]["DSS"] = _myds->DSS; if (_myds->myconn) { MySQL_Connection * _myconn = _myds->myconn; + for (auto idx = 0; idx < SQL_NAME_LAST; idx++) { + _myconn->variables[idx].fill_server_internal_session(j, i, idx); + } sprintf(buff,"%p",_myconn); j["backends"][i]["conn"]["address"] = buff; j["backends"][i]["conn"]["auto_increment_delay_token"] = _myconn->auto_increment_delay_token; @@ -1011,17 +1009,6 @@ void MySQL_Session::generate_proxysql_internal_session_json(json &j) { j["backends"][i]["conn"]["questions"] = _myconn->statuses.questions; j["backends"][i]["conn"]["myconnpoll_get"] = _myconn->statuses.myconnpoll_get; j["backends"][i]["conn"]["myconnpoll_put"] = _myconn->statuses.myconnpoll_put; - j["backends"][i]["conn"]["sql_mode"] = ( _myconn->options.sql_mode ? _myconn->options.sql_mode : "") ; - j["backends"][i]["conn"]["sql_mode_sent"] = _myds->myconn->options.sql_mode_sent; - j["backends"][i]["conn"]["time_zone"] = ( _myconn->options.time_zone ? _myconn->options.time_zone : "") ; - j["backends"][i]["conn"]["isolation_level"] = ( _myconn->options.isolation_level ? _myconn->options.isolation_level : "") ; - j["backends"][i]["conn"]["tx_isolation"] = ( _myconn->options.tx_isolation ? _myconn->options.tx_isolation : "") ; - j["backends"][i]["conn"]["transaction_read"] = ( _myconn->options.transaction_read ? _myconn->options.transaction_read : "") ; - j["backends"][i]["conn"]["character_set_results"] = ( _myconn->options.character_set_results ? _myconn->options.character_set_results : "") ; - j["backends"][i]["conn"]["session_track_gtids"] = ( _myconn->options.session_track_gtids ? _myconn->options.session_track_gtids : "") ; - j["backends"][i]["conn"]["sql_auto_is_null"] = ( _myconn->options.sql_auto_is_null ? _myconn->options.sql_auto_is_null : "") ; - j["backends"][i]["conn"]["sql_select_limit"] = ( _myconn->options.sql_select_limit ? _myconn->options.sql_select_limit : "") ; - j["backends"][i]["conn"]["sql_safe_updates"] = ( _myconn->options.sql_safe_updates ? _myconn->options.sql_safe_updates : "") ; j["backends"][i]["conn"]["collation_connection"] = ( _myconn->options.collation_connection ? _myconn->options.collation_connection : "") ; j["backends"][i]["conn"]["net_write_timeout"] = ( _myconn->options.net_write_timeout ? _myconn->options.net_write_timeout : "") ; j["backends"][i]["conn"]["max_join_size"] = ( _myconn->options.max_join_size ? _myconn->options.max_join_size : "") ; @@ -1645,45 +1632,6 @@ bool MySQL_Session::handler_again___verify_backend_sql_log_bin() { return false; } -bool MySQL_Session::handler_again___verify_backend_sql_mode() { - bool ret = false; - proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.sql_mode, mybe->server_myds->myconn->options.sql_mode); - ret = handler_again___verify_backend__generic_variable( - &mybe->server_myds->myconn->options.sql_mode_int, - &mybe->server_myds->myconn->options.sql_mode, - mysql_thread___default_sql_mode, - &client_myds->myconn->options.sql_mode_int, - client_myds->myconn->options.sql_mode, - SETTING_SQL_MODE - ); - return ret; -/* - // for sql_mode we also set sql_mode_sent . Doesn't seem used tho. - // snippet, for reference - if ( - (client_myds->myconn->options.sql_mode_int != mybe->server_myds->myconn->options.sql_mode_int) - || - (mybe->server_myds->myconn->options.sql_mode_sent == false) - ) { - mybe->server_myds->myconn->options.sql_mode_sent = true; -*/ - -} - -bool MySQL_Session::handler_again___verify_backend_time_zone() { - bool ret = false; - proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.time_zone, mybe->server_myds->myconn->options.time_zone); - ret = handler_again___verify_backend__generic_variable( - &mybe->server_myds->myconn->options.time_zone_int, - &mybe->server_myds->myconn->options.time_zone, - mysql_thread___default_time_zone, - &client_myds->myconn->options.time_zone_int, - client_myds->myconn->options.time_zone, - SETTING_TIME_ZONE - ); - return ret; -} - bool MySQL_Session::handler_again___verify_backend__generic_variable(uint32_t *be_int, char **be_var, char *def, uint32_t *fe_int, char *fe_var, enum session_status next_sess_status) { // be_int = backend int (hash) // be_var = backend value @@ -1732,115 +1680,10 @@ bool MySQL_Session::handler_again___verify_backend__generic_variable(uint32_t *b return false; } -bool MySQL_Session::handler_again___verify_backend_isolation_level() { - bool ret = false; - proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.isolation_level, mybe->server_myds->myconn->options.isolation_level); - ret = handler_again___verify_backend__generic_variable( - &mybe->server_myds->myconn->options.isolation_level_int, - &mybe->server_myds->myconn->options.isolation_level, - mysql_thread___default_isolation_level, - &client_myds->myconn->options.isolation_level_int, - client_myds->myconn->options.isolation_level, - SETTING_ISOLATION_LEVEL - ); - return ret; -} - -bool MySQL_Session::handler_again___verify_backend_transaction_read() { - bool ret = false; - proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.transaction_read, mybe->server_myds->myconn->options.transaction_read); - ret = handler_again___verify_backend__generic_variable( - &mybe->server_myds->myconn->options.transaction_read_int, - &mybe->server_myds->myconn->options.transaction_read, - mysql_thread___default_transaction_read, - &client_myds->myconn->options.transaction_read_int, - client_myds->myconn->options.transaction_read, - SETTING_TRANSACTION_READ - ); - return ret; -} - -bool MySQL_Session::handler_again___verify_backend_tx_isolation() { - bool ret = false; - proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.tx_isolation, mybe->server_myds->myconn->options.tx_isolation); - ret = handler_again___verify_backend__generic_variable( - &mybe->server_myds->myconn->options.tx_isolation_int, - &mybe->server_myds->myconn->options.tx_isolation, - mysql_thread___default_tx_isolation, - &client_myds->myconn->options.tx_isolation_int, - client_myds->myconn->options.tx_isolation, - SETTING_TX_ISOLATION - ); - return ret; -} - -bool MySQL_Session::handler_again___verify_backend_character_set_results() { - bool ret = false; - proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.character_set_results, mybe->server_myds->myconn->options.character_set_results); - ret = handler_again___verify_backend__generic_variable( - &mybe->server_myds->myconn->options.character_set_results_int, - &mybe->server_myds->myconn->options.character_set_results, - mysql_thread___default_character_set_results, - &client_myds->myconn->options.character_set_results_int, - client_myds->myconn->options.character_set_results, - SETTING_CHARACTER_SET_RESULTS - ); - return ret; -} - -bool MySQL_Session::handler_again___verify_backend_session_track_gtids() { - bool ret = false; - proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.session_track_gtids, mybe->server_myds->myconn->options.session_track_gtids); - ret = handler_again___verify_backend__generic_variable( - &mybe->server_myds->myconn->options.session_track_gtids_int, - &mybe->server_myds->myconn->options.session_track_gtids, - mysql_thread___default_session_track_gtids, - &client_myds->myconn->options.session_track_gtids_int, - client_myds->myconn->options.session_track_gtids, - SETTING_SESSION_TRACK_GTIDS - ); - return ret; -} - -bool MySQL_Session::handler_again___verify_backend_sql_auto_is_null() { - bool ret = false; - proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.sql_auto_is_null, mybe->server_myds->myconn->options.sql_auto_is_null); - ret = handler_again___verify_backend__generic_variable( - &mybe->server_myds->myconn->options.sql_auto_is_null_int, - &mybe->server_myds->myconn->options.sql_auto_is_null, - mysql_thread___default_sql_auto_is_null, - &client_myds->myconn->options.sql_auto_is_null_int, - client_myds->myconn->options.sql_auto_is_null, - SETTING_SQL_AUTO_IS_NULL - ); - return ret; -} - -bool MySQL_Session::handler_again___verify_backend_sql_select_limit() { - bool ret = false; - proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.sql_select_limit, mybe->server_myds->myconn->options.sql_select_limit); - ret = handler_again___verify_backend__generic_variable( - &mybe->server_myds->myconn->options.sql_select_limit_int, - &mybe->server_myds->myconn->options.sql_select_limit, - mysql_thread___default_sql_select_limit, - &client_myds->myconn->options.sql_select_limit_int, - client_myds->myconn->options.sql_select_limit, - SETTING_SQL_SELECT_LIMIT - ); - return ret; -} - -bool MySQL_Session::handler_again___verify_backend_sql_safe_updates() { +bool MySQL_Session::handler_again___verify_backend(int var) { bool ret = false; - proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.sql_safe_updates, mybe->server_myds->myconn->options.sql_safe_updates); - ret = handler_again___verify_backend__generic_variable( - &mybe->server_myds->myconn->options.sql_safe_updates_int, - &mybe->server_myds->myconn->options.sql_safe_updates, - mysql_thread___default_sql_safe_updates, - &client_myds->myconn->options.sql_safe_updates_int, - client_myds->myconn->options.sql_safe_updates, - SETTING_SQL_SAFE_UPDATES - ); + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, mysql_variables->client_get_value(var), mysql_variables->server_get_value(var)); + ret = mysql_variables->verify_variable(var); return ret; } @@ -2340,13 +2183,6 @@ bool MySQL_Session::handler_again___status_SETTING_SQL_LOG_BIN(int *_rc) { return ret; } -bool MySQL_Session::handler_again___status_SETTING_SQL_MODE(int *_rc) { - bool ret=false; - assert(mybe->server_myds->myconn); - ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SQL_MODE", mybe->server_myds->myconn->options.sql_mode); - return ret; -} - /* FIXME: this old code hardcoded the handling of issue 1738 // this seems unnecessary/redundant // leaving the code for further reference, to be removed later @@ -2453,7 +2289,7 @@ bool MySQL_Session::handler_again___status_SETTING_SQL_MODE(int *_rc) { } */ -bool MySQL_Session::handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, char *var_name, char *var_value, bool no_quote, bool set_transaction) { +bool MySQL_Session::handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, const char *var_name, const char *var_value, bool no_quote, bool set_transaction) { bool ret = false; assert(mybe->server_myds->myconn); MySQL_Data_Stream *myds=mybe->server_myds; @@ -2576,20 +2412,6 @@ bool MySQL_Session::handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, ch return ret; } -bool MySQL_Session::handler_again___status_SETTING_TIME_ZONE(int *_rc) { - bool ret=false; - assert(mybe->server_myds->myconn); - ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"TIME_ZONE", mybe->server_myds->myconn->options.time_zone); - return ret; -} - -bool MySQL_Session::handler_again___status_SETTING_ISOLATION_LEVEL(int *_rc) { - bool ret=false; - assert(mybe->server_myds->myconn); - ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SESSION TRANSACTION ISOLATION LEVEL", mybe->server_myds->myconn->options.isolation_level, false, true); - return ret; -} - bool MySQL_Session::handler_again___status_SETTING_MULTI_STMT(int *_rc) { assert(mybe->server_myds->myconn); MySQL_Data_Stream *myds=mybe->server_myds; @@ -2621,52 +2443,17 @@ bool MySQL_Session::handler_again___status_SETTING_CHARSET(int *_rc) { return ret; } -bool MySQL_Session::handler_again___status_SETTING_TRANSACTION_READ(int *_rc) { - bool ret=false; - assert(mybe->server_myds->myconn); - ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SESSION TRANSACTION READ", mybe->server_myds->myconn->options.transaction_read, false, true); - return ret; -} - -bool MySQL_Session::handler_again___status_SETTING_TX_ISOLATION(int *_rc) { - bool ret=false; - assert(mybe->server_myds->myconn); - ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"TX_ISOLATION", mybe->server_myds->myconn->options.tx_isolation, false, false); - return ret; -} - -bool MySQL_Session::handler_again___status_SETTING_CHARACTER_SET_RESULTS(int *_rc) { - bool ret=false; - assert(mybe->server_myds->myconn); - ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"CHARACTER_SET_RESULTS", mybe->server_myds->myconn->options.character_set_results, true); - return ret; -} - -bool MySQL_Session::handler_again___status_SETTING_SESSION_TRACK_GTIDS(int *_rc) { - bool ret=false; - assert(mybe->server_myds->myconn); - ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SESSION_TRACK_GTIDS", mybe->server_myds->myconn->options.session_track_gtids, true); - return ret; -} - -bool MySQL_Session::handler_again___status_SETTING_SQL_AUTO_IS_NULL(int *_rc) { - bool ret=false; - assert(mybe->server_myds->myconn); - ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SQL_AUTO_IS_NULL", mybe->server_myds->myconn->options.sql_auto_is_null, true); - return ret; -} - bool MySQL_Session::handler_again___status_SETTING_SQL_SELECT_LIMIT(int *_rc) { bool ret=false; assert(mybe->server_myds->myconn); - ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SQL_SELECT_LIMIT", mybe->server_myds->myconn->options.sql_select_limit, true); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SQL_SELECT_LIMIT", mysql_variables->server_get_value(SQL_SELECT_LIMIT), true); return ret; } bool MySQL_Session::handler_again___status_SETTING_SQL_SAFE_UPDATES(int *_rc) { bool ret=false; assert(mybe->server_myds->myconn); - ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SQL_SAFE_UPDATES", mybe->server_myds->myconn->options.sql_safe_updates, true); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SQL_SAFE_UPDATES", mysql_variables->server_get_value(SQL_SAFE_UPDATES), true); return ret; } @@ -3996,40 +3783,17 @@ handler_again: goto handler_again; } if (locked_on_hostgroup == -1 || locked_on_hostgroup_and_all_variables_set == false ) { + if (handler_again___verify_backend_charset()) { goto handler_again; } - if (handler_again___verify_backend_sql_log_bin()) { - goto handler_again; - } - if (handler_again___verify_backend_sql_mode()) { - goto handler_again; - } - if (handler_again___verify_backend_time_zone()) { - goto handler_again; - } - if (handler_again___verify_backend_isolation_level()) { - goto handler_again; - } - if (handler_again___verify_backend_transaction_read()) { - goto handler_again; - } - if (handler_again___verify_backend_tx_isolation()) { - goto handler_again; - } - if (handler_again___verify_backend_character_set_results()) { - goto handler_again; - } - if (handler_again___verify_backend_session_track_gtids()) { - goto handler_again; - } - if (handler_again___verify_backend_sql_auto_is_null()) { - goto handler_again; - } - if (handler_again___verify_backend_sql_select_limit()) { - goto handler_again; + + for (auto i = 0; i < SQL_NAME_LAST; i++) { + if(mysql_variables->verify_variable(i)) + goto handler_again; } - if (handler_again___verify_backend_sql_safe_updates()) { + + if (handler_again___verify_backend_sql_log_bin()) { goto handler_again; } if (handler_again___verify_backend_collation_connection()) { @@ -4581,120 +4345,20 @@ handler_again: break; case SETTING_SQL_MODE: - { - int rc=0; - if (handler_again___status_SETTING_SQL_MODE(&rc)) - goto handler_again; // we changed status - if (rc==-1) { // we have an error we can't handle - handler_ret = -1; - return handler_ret; - } - } - break; - + case SETTING_SQL_SELECT_LIMIT: + case SETTING_SQL_SAFE_UPDATES: case SETTING_TIME_ZONE: - { - int rc=0; - if (handler_again___status_SETTING_TIME_ZONE(&rc)) - goto handler_again; // we changed status - if (rc==-1) { // we have an error we can't handle - handler_ret = -1; - return handler_ret; - } - } - break; - + case SETTING_CHARACTER_SET_RESULTS: case SETTING_ISOLATION_LEVEL: - { - int rc=0; - if (handler_again___status_SETTING_ISOLATION_LEVEL(&rc)) - goto handler_again; // we changed status - if (rc==-1) { // we have an error we can't handle - handler_ret = -1; - return handler_ret; - } - } - break; - case SETTING_TRANSACTION_READ: - { - int rc=0; - if (handler_again___status_SETTING_TRANSACTION_READ(&rc)) - goto handler_again; // we changed status - if (rc==-1) { // we have an error we can't handle - handler_ret = -1; - return handler_ret; - } - } - break; - - case SETTING_TX_ISOLATION: - { - int rc=0; - if (handler_again___status_SETTING_TX_ISOLATION(&rc)) - goto handler_again; // we changed status - if (rc==-1) { // we have an error we can't handle - handler_ret = -1; - return handler_ret; - } - } - break; - - - case SETTING_CHARACTER_SET_RESULTS: - { - int rc=0; - if (handler_again___status_SETTING_CHARACTER_SET_RESULTS(&rc)) - goto handler_again; // we changed status - if (rc==-1) { // we have an error we can't handle - handler_ret = -1; - return handler_ret; - } - } - break; - case SETTING_SESSION_TRACK_GTIDS: - { - int rc=0; - if (handler_again___status_SETTING_SESSION_TRACK_GTIDS(&rc)) - goto handler_again; // we changed status - if (rc==-1) { // we have an error we can't handle - handler_ret = -1; - return handler_ret; - } - } - break; - case SETTING_SQL_AUTO_IS_NULL: - { - int rc=0; - if (handler_again___status_SETTING_SQL_AUTO_IS_NULL(&rc)) - goto handler_again; // we changed status - if (rc==-1) { // we have an error we can't handle - handler_ret = -1; - return handler_ret; - } - } - break; - - case SETTING_SQL_SELECT_LIMIT: - { - int rc=0; - if (handler_again___status_SETTING_SQL_SELECT_LIMIT(&rc)) - goto handler_again; // we changed status - if (rc==-1) { // we have an error we can't handle - handler_ret = -1; - return handler_ret; + for (auto i = 0; i < SQL_NAME_LAST; i++) { + int rc = 0; + if (mysql_variables->update_variable(rc)) { + goto handler_again; } - } - break; - - case SETTING_SQL_SAFE_UPDATES: - { - int rc=0; - if (handler_again___status_SETTING_SQL_SAFE_UPDATES(&rc)) - goto handler_again; // we changed status - if (rc==-1) { // we have an error we can't handle + if (rc == -1) { handler_ret = -1; return handler_ret; } @@ -5640,17 +5304,9 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET SQL Mode value %s\n", value1.c_str()); uint32_t sql_mode_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); - if (client_myds->myconn->options.sql_mode_int != sql_mode_int) { - //fprintf(stderr,"sql_mode_int='%u'\n", sql_mode_int); - client_myds->myconn->options.sql_mode_int = sql_mode_int; - if (client_myds->myconn->options.sql_mode) { - free(client_myds->myconn->options.sql_mode); - } + if (mysql_variables->client_get_hash(SQL_SQL_MODE) != sql_mode_int) { + mysql_variables->client_set_value(SQL_SQL_MODE, value1.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection SQL Mode to %s\n", value1.c_str()); - client_myds->myconn->options.sql_mode=strdup(value1.c_str()); - if (strcasestr(value1.c_str(), (char *)"NO_BACKSLASH_ESCAPES")) { - //goto __exit_set_destination_hostgroup; - } } exit_after_SetParse = true; } else if (var == "sql_auto_is_null") { @@ -5675,13 +5331,9 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C if (__tmp_value >= 0) { proxy_debug(PROXY_DEBUG_MYSQL_COM, 7, "Processing SET sql_auto_is_null value %s\n", value1.c_str()); uint32_t sql_auto_is_null_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); - if (client_myds->myconn->options.sql_auto_is_null_int != sql_auto_is_null_int) { - client_myds->myconn->options.sql_auto_is_null_int = sql_auto_is_null_int; - if (client_myds->myconn->options.sql_auto_is_null) { - free(client_myds->myconn->options.sql_auto_is_null); - } + if (mysql_variables->client_get_hash(SQL_SQL_AUTO_IS_NULL) != sql_auto_is_null_int) { + mysql_variables->client_set_value(SQL_SQL_AUTO_IS_NULL, value1.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection sql_auto_is_null to %s\n", value1.c_str()); - client_myds->myconn->options.sql_auto_is_null=strdup(value1.c_str()); } exit_after_SetParse = true; } else { @@ -5710,13 +5362,9 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C if (__tmp_value >= 0) { proxy_debug(PROXY_DEBUG_MYSQL_COM, 7, "Processing SET sql_safe_updates value %s\n", value1.c_str()); uint32_t sql_safe_updates_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); - if (client_myds->myconn->options.sql_safe_updates_int != sql_safe_updates_int) { - client_myds->myconn->options.sql_safe_updates_int = sql_safe_updates_int; - if (client_myds->myconn->options.sql_safe_updates) { - free(client_myds->myconn->options.sql_safe_updates); - } + if (mysql_variables->client_get_hash(SQL_SAFE_UPDATES) != sql_safe_updates_int) { + mysql_variables->client_set_value(SQL_SAFE_UPDATES, value1.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection sql_safe_updates to %s\n", value1.c_str()); - client_myds->myconn->options.sql_safe_updates=strdup(value1.c_str()); } exit_after_SetParse = true; } else { @@ -5789,14 +5437,9 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET Time Zone value %s\n", value1.c_str()); uint32_t time_zone_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); - if (client_myds->myconn->options.time_zone_int != time_zone_int) { - //fprintf(stderr,"time_zone_int='%u'\n", time_zone_int); - client_myds->myconn->options.time_zone_int = time_zone_int; - if (client_myds->myconn->options.time_zone) { - free(client_myds->myconn->options.time_zone); - } + if (mysql_variables->client_get_hash(SQL_TIME_ZONE) != time_zone_int) { + mysql_variables->client_set_value(SQL_TIME_ZONE, value1.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection Time zone to %s\n", value1.c_str()); - client_myds->myconn->options.time_zone=strdup(value1.c_str()); } exit_after_SetParse = true; } else if (var == "session_track_gtids") { @@ -5804,13 +5447,9 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C if ((strcasecmp(value1.c_str(),"OWN_GTID")==0) || (strcasecmp(value1.c_str(),"OFF")==0)) { proxy_debug(PROXY_DEBUG_MYSQL_COM, 7, "Processing SET session_track_gtids value %s\n", value1.c_str()); uint32_t session_track_gtids_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); - if (client_myds->myconn->options.session_track_gtids_int != session_track_gtids_int) { - client_myds->myconn->options.session_track_gtids_int = session_track_gtids_int; - if (client_myds->myconn->options.session_track_gtids) { - free(client_myds->myconn->options.session_track_gtids); - } + if (mysql_variables->client_get_hash(SQL_SESSION_TRACK_GTIDS) != session_track_gtids_int) { + mysql_variables->client_set_value(SQL_SESSION_TRACK_GTIDS, value1.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection session_track_gtids to %s\n", value1.c_str()); - client_myds->myconn->options.session_track_gtids=strdup(value1.c_str()); } exit_after_SetParse = true; } else { @@ -5887,13 +5526,9 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C if (only_digit_chars) { proxy_debug(PROXY_DEBUG_MYSQL_COM, 7, "Processing SET sql_select_limit value %s\n", value1.c_str()); uint32_t sql_select_limit_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); - if (client_myds->myconn->options.sql_select_limit_int != sql_select_limit_int) { - client_myds->myconn->options.sql_select_limit_int = sql_select_limit_int; - if (client_myds->myconn->options.sql_select_limit) { - free(client_myds->myconn->options.sql_select_limit); - } + if (mysql_variables->client_get_hash(SQL_SELECT_LIMIT) != sql_select_limit_int) { + mysql_variables->client_set_value(SQL_SELECT_LIMIT, value1.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection sql_select_limit to %s\n", value1.c_str()); - client_myds->myconn->options.sql_select_limit=strdup(value1.c_str()); } exit_after_SetParse = true; } else { @@ -5939,13 +5574,9 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C if (only_normal_chars) { proxy_debug(PROXY_DEBUG_MYSQL_COM, 7, "Processing SET character_set_results value %s\n", value1.c_str()); uint32_t character_set_results_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); - if (client_myds->myconn->options.character_set_results_int != character_set_results_int) { - client_myds->myconn->options.character_set_results_int = character_set_results_int; - if (client_myds->myconn->options.character_set_results) { - free(client_myds->myconn->options.character_set_results); - } + if (mysql_variables->client_get_hash(SQL_CHARACTER_SET_RESULTS) != character_set_results_int) { + mysql_variables->client_set_value(SQL_CHARACTER_SET_RESULTS, value1.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection character_set_results to %s\n", value1.c_str()); - client_myds->myconn->options.character_set_results=strdup(value1.c_str()); } exit_after_SetParse = true; } else { @@ -5995,15 +5626,13 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } else if (var == "tx_isolation") { std::string value1 = *values; proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET tx_isolation value %s\n", value1.c_str()); - uint32_t tx_isolation_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); - if (client_myds->myconn->options.tx_isolation_int != tx_isolation_int) { - //fprintf(stderr,"sql_mode_int='%u'\n", sql_mode_int); - client_myds->myconn->options.tx_isolation_int = tx_isolation_int; - if (client_myds->myconn->options.tx_isolation) { - free(client_myds->myconn->options.tx_isolation); - } + auto pos = value1.find('-'); + if (pos != std::string::npos) + value1[pos] = ' '; + uint32_t isolation_level_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); + if (mysql_variables->client_get_hash(SQL_ISOLATION_LEVEL) != isolation_level_int) { + mysql_variables->client_set_value(SQL_ISOLATION_LEVEL, value1.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection TX ISOLATION to %s\n", value1.c_str()); - client_myds->myconn->options.tx_isolation=strdup(value1.c_str()); } exit_after_SetParse = true; } else { @@ -6048,12 +5677,8 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C delete opt2; if (rc) { uint32_t sql_mode_int=SpookyHash::Hash32(s1.c_str(),s1.length(),10); - if (client_myds->myconn->options.sql_mode_int != sql_mode_int) { - client_myds->myconn->options.sql_mode_int = sql_mode_int; - if (client_myds->myconn->options.sql_mode) { - free(client_myds->myconn->options.sql_mode); - } - client_myds->myconn->options.sql_mode=strdup(s1.c_str()); + if (mysql_variables->client_get_hash(SQL_SQL_MODE) != sql_mode_int) { + mysql_variables->client_set_value(SQL_SQL_MODE, s1.c_str()); std::size_t found_at = s1.find("@"); if (found_at != std::string::npos) { char *v1 = strdup(s1.c_str()); @@ -6120,26 +5745,18 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C std::string value1 = *values; proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET SESSION TRANSACTION ISOLATION LEVEL value %s\n", value1.c_str()); uint32_t isolation_level_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); - if (client_myds->myconn->options.isolation_level_int != isolation_level_int) { - client_myds->myconn->options.isolation_level_int = isolation_level_int; - if (client_myds->myconn->options.isolation_level) { - free(client_myds->myconn->options.isolation_level); - } + if (mysql_variables->client_get_hash(SQL_ISOLATION_LEVEL) != isolation_level_int) { + mysql_variables->client_set_value(SQL_ISOLATION_LEVEL, value1.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection TRANSACTION ISOLATION LEVEL to %s\n", value1.c_str()); - client_myds->myconn->options.isolation_level=strdup(value1.c_str()); } exit_after_SetParse = true; } else if (var == "read") { std::string value1 = *values; proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET SESSION TRANSACTION READ value %s\n", value1.c_str()); uint32_t transaction_read_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); - if (client_myds->myconn->options.transaction_read_int != transaction_read_int) { - client_myds->myconn->options.transaction_read_int = transaction_read_int; - if (client_myds->myconn->options.transaction_read) { - free(client_myds->myconn->options.transaction_read); - } + if (mysql_variables->client_get_hash(SQL_TRANSACTION_READ) != transaction_read_int) { + mysql_variables->client_set_value(SQL_TRANSACTION_READ, value1.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection TRANSACTION READ to %s\n", value1.c_str()); - client_myds->myconn->options.transaction_read=strdup(value1.c_str()); } exit_after_SetParse = true; } else { diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index e97132a0a..5272ec098 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -14,6 +14,7 @@ #include "StatCounters.h" #include "MySQL_PreparedStatement.h" #include "MySQL_Logger.hpp" +#include "MySQL_Variables.h" #ifdef DEBUG MySQL_Session *sess_stopat; @@ -3567,69 +3568,16 @@ MySQL_Session * MySQL_Thread::create_new_session_and_client_data_stream(int _fd) sess->client_myds->myprot.init(&sess->client_myds, sess->client_myds->myconn->userinfo, sess); - // fix bug 1253 : initialize time_zone - uint32_t time_zone_int=SpookyHash::Hash32(mysql_thread___default_time_zone,strlen(mysql_thread___default_time_zone),10); - sess->client_myds->myconn->options.time_zone_int = time_zone_int; - if (sess->client_myds->myconn->options.time_zone) { - free(sess->client_myds->myconn->options.time_zone); - } - sess->client_myds->myconn->options.time_zone=strdup(mysql_thread___default_time_zone); - - uint32_t isolation_level_int=SpookyHash::Hash32(mysql_thread___default_isolation_level,strlen(mysql_thread___default_isolation_level),10); - sess->client_myds->myconn->options.isolation_level_int = isolation_level_int; - if (sess->client_myds->myconn->options.isolation_level) { - free(sess->client_myds->myconn->options.isolation_level); - } - sess->client_myds->myconn->options.isolation_level=strdup(mysql_thread___default_isolation_level); - - uint32_t tx_isolation_int=SpookyHash::Hash32(mysql_thread___default_tx_isolation,strlen(mysql_thread___default_tx_isolation),10); - sess->client_myds->myconn->options.tx_isolation_int = tx_isolation_int; - if (sess->client_myds->myconn->options.tx_isolation) { - free(sess->client_myds->myconn->options.tx_isolation); - } - sess->client_myds->myconn->options.tx_isolation=strdup(mysql_thread___default_tx_isolation); - - uint32_t transaction_read_int=SpookyHash::Hash32(mysql_thread___default_transaction_read,strlen(mysql_thread___default_transaction_read),10); - sess->client_myds->myconn->options.transaction_read_int = transaction_read_int; - if (sess->client_myds->myconn->options.transaction_read) { - free(sess->client_myds->myconn->options.transaction_read); - } - sess->client_myds->myconn->options.transaction_read=strdup(mysql_thread___default_transaction_read); - - uint32_t character_set_results_int=SpookyHash::Hash32(mysql_thread___default_character_set_results,strlen(mysql_thread___default_character_set_results),10); - sess->client_myds->myconn->options.character_set_results_int = character_set_results_int; - if (sess->client_myds->myconn->options.character_set_results) { - free(sess->client_myds->myconn->options.character_set_results); - } - sess->client_myds->myconn->options.character_set_results=strdup(mysql_thread___default_character_set_results); - - uint32_t session_track_gtids_int=SpookyHash::Hash32(mysql_thread___default_session_track_gtids,strlen(mysql_thread___default_session_track_gtids),10); - sess->client_myds->myconn->options.session_track_gtids_int = session_track_gtids_int; - if (sess->client_myds->myconn->options.session_track_gtids) { - free(sess->client_myds->myconn->options.session_track_gtids); - } - sess->client_myds->myconn->options.session_track_gtids=strdup(mysql_thread___default_session_track_gtids); - - uint32_t sql_auto_is_null_int=SpookyHash::Hash32(mysql_thread___default_sql_auto_is_null,strlen(mysql_thread___default_sql_auto_is_null),10); - sess->client_myds->myconn->options.sql_auto_is_null_int = sql_auto_is_null_int; - if (sess->client_myds->myconn->options.sql_auto_is_null) { - free(sess->client_myds->myconn->options.sql_auto_is_null); - } - sess->client_myds->myconn->options.sql_auto_is_null=strdup(mysql_thread___default_sql_auto_is_null); - - uint32_t sql_select_limit_int=SpookyHash::Hash32(mysql_thread___default_sql_select_limit,strlen(mysql_thread___default_sql_select_limit),10); - sess->client_myds->myconn->options.sql_select_limit_int = sql_select_limit_int; - if (sess->client_myds->myconn->options.sql_select_limit) { - free(sess->client_myds->myconn->options.sql_select_limit); - } - sess->client_myds->myconn->options.sql_select_limit=strdup(mysql_thread___default_sql_select_limit); - uint32_t sql_safe_updates_int=SpookyHash::Hash32(mysql_thread___default_sql_safe_updates,strlen(mysql_thread___default_sql_safe_updates),10); - sess->client_myds->myconn->options.sql_safe_updates_int = sql_safe_updates_int; - if (sess->client_myds->myconn->options.sql_safe_updates) { - free(sess->client_myds->myconn->options.sql_safe_updates); - } - sess->client_myds->myconn->options.sql_safe_updates=strdup(mysql_thread___default_sql_safe_updates); + sess->mysql_variables->client_set_value(SQL_SELECT_LIMIT, mysql_thread___default_sql_select_limit); + sess->mysql_variables->client_set_value(SQL_SAFE_UPDATES, mysql_thread___default_sql_safe_updates); + sess->mysql_variables->client_set_value(SQL_SQL_MODE, mysql_thread___default_sql_mode); + sess->mysql_variables->client_set_value(SQL_TIME_ZONE, mysql_thread___default_time_zone); + sess->mysql_variables->client_set_value(SQL_CHARACTER_SET_RESULTS, mysql_thread___default_character_set_results); + sess->mysql_variables->client_set_value(SQL_ISOLATION_LEVEL, mysql_thread___default_isolation_level); + sess->mysql_variables->client_set_value(SQL_TRANSACTION_READ, mysql_thread___default_transaction_read); + sess->mysql_variables->client_set_value(SQL_SESSION_TRACK_GTIDS, mysql_thread___default_session_track_gtids); + sess->mysql_variables->client_set_value(SQL_SQL_AUTO_IS_NULL, mysql_thread___default_sql_auto_is_null); uint32_t collation_connection_int=SpookyHash::Hash32(mysql_thread___default_collation_connection,strlen(mysql_thread___default_collation_connection),10); sess->client_myds->myconn->options.collation_connection_int = collation_connection_int; diff --git a/lib/MySQL_Variables.cpp b/lib/MySQL_Variables.cpp new file mode 100644 index 000000000..a61e937ea --- /dev/null +++ b/lib/MySQL_Variables.cpp @@ -0,0 +1,230 @@ +#include "MySQL_Variables.h" +#include "proxysql.h" + +#include "MySQL_Session.h" +#include "MySQL_Data_Stream.h" +#include "SpookyV2.h" + +int MySQL_Variables::session_by_var[SQL_NAME_LAST] = { + SETTING_SQL_SAFE_UPDATES, + SETTING_SQL_SELECT_LIMIT, + SETTING_SQL_MODE, + SETTING_TIME_ZONE, + SETTING_CHARACTER_SET_RESULTS, + SETTING_ISOLATION_LEVEL, + SETTING_TRANSACTION_READ, + SETTING_SESSION_TRACK_GTIDS, + SETTING_SQL_AUTO_IS_NULL +/* SETTING_COLLATION_CONNECTION, + SETTING_NET_WRITE_TIMEOUT, + SETTING_MAX_JOIN_SIZE*/ +}; + +bool MySQL_Variables::quotes[SQL_NAME_LAST] = { + true, // SQL_SAFE_UPDATES + true, // SQL_SELECT_LIMIT + false, // SQL_MODE + false, // SQL_TIME_ZONE + true, // CHARACTER_SET_RESULTS + false, // ISOLATION_LEVEL + false, // TRANSACTION_READ + true, // SESSION_TRACK_GTIDS + true // SQL_AUTO_IS_NULL +/* false, // COLLATION_CONNECTION + true, // NET_WRITE_TIMEOUT + true // MAX_JOIN_SIZE*/ +}; + +bool MySQL_Variables::set_transaction[SQL_NAME_LAST] = { + false, // SQL_SAFE_UPDATES + false, // SQL_SELECT_LIMIT + false, // SQL_MODE + false, // SQL_TIME_ZONE + false, // CHARACTER_SET_RESULTS + true, // ISOLATION_LEVEL + true, // TRANSACTION_READ + false, // SESSION_TRACK_GTIDS + false // SQL_AUTO_IS_NULL +/* false, // COLLATION_CONNECTION + false, // NET_WRITE_TIMEOUT + false // MAX_JOIN_SIZE */ +}; + +int MySQL_Variables::var_by_session[NONE] = { + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_SQL_MODE, + SQL_TIME_ZONE, + SQL_ISOLATION_LEVEL, + SQL_TRANSACTION_READ, + SQL_CHARACTER_SET_RESULTS, + SQL_SESSION_TRACK_GTIDS, + SQL_SQL_AUTO_IS_NULL, + SQL_SELECT_LIMIT, + SQL_SAFE_UPDATES, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST, + SQL_NAME_LAST +}; + +MySQL_Variables::MySQL_Variables(MySQL_Session* _session) { + assert(_session); + session = _session; + + for (auto i = 0; i < SQL_NAME_LAST; i++) { + switch(i) { + case SQL_SAFE_UPDATES: + case SQL_SELECT_LIMIT: + case SQL_SQL_MODE: + case SQL_TIME_ZONE: + case SQL_CHARACTER_SET_RESULTS: + case SQL_ISOLATION_LEVEL: + case SQL_TRANSACTION_READ: + case SQL_SESSION_TRACK_GTIDS: + case SQL_SQL_AUTO_IS_NULL: + updaters[i] = new Generic_Updater(); + break; + default: + proxy_error("Wrong variable index\n"); + assert(0); + } + } +} + +MySQL_Variables::~MySQL_Variables() { + for (auto u : updaters) + delete u; +} + +void MySQL_Variables::client_set_value(int idx, const char* value) { + session->client_myds->myconn->variables[idx].hash = SpookyHash::Hash32(value,strlen(value),10); + + if (session->client_myds->myconn->variables[idx].value) { + free(session->client_myds->myconn->variables[idx].value); + } + session->client_myds->myconn->variables[idx].value = strdup(value); +} + +const char* MySQL_Variables::client_get_value(int idx) { + return session->client_myds->myconn->variables[idx].value; +} + +uint32_t MySQL_Variables::client_get_hash(int idx) { + return session->client_myds->myconn->variables[idx].hash; +} + +void MySQL_Variables::server_set_value(int idx, const char* value) { + session->mybe->server_myds->myconn->variables[idx].hash = SpookyHash::Hash32(value,strlen(value),10); + + if (session->mybe->server_myds->myconn->variables[idx].value) { + free(session->mybe->server_myds->myconn->variables[idx].value); + } + session->mybe->server_myds->myconn->variables[idx].value = strdup(value); +} + +const char* MySQL_Variables::server_get_value(int idx) { + return session->mybe->server_myds->myconn->variables[idx].value; +} + +uint32_t MySQL_Variables::server_get_hash(int idx) { + return session->mybe->server_myds->myconn->variables[idx].hash; +} + +bool MySQL_Variables::verify_generic_variable(uint32_t *be_int, char **be_var, char *def, uint32_t *fe_int, char *fe_var, enum session_status next_sess_status) { + // be_int = backend int (hash) + // be_var = backend value + // def = default + // fe_int = frontend int (has) + // fe_var = frontend value + if (*be_int == 0) { + // it is the first time we use this backend. Set value to default + if (*be_var) { + free(*be_var); + *be_var = NULL; + } + *be_var = strdup(def); + uint32_t tmp_int = SpookyHash::Hash32(*be_var, strlen(*be_var), 10); + *be_int = tmp_int; + } + if (*fe_int) { + if (*fe_int != *be_int) { + { + *be_int = *fe_int; + if (*be_var) { + free(*be_var); + *be_var = NULL; + } + if (fe_var) { + *be_var = strdup(fe_var); + } + } + switch(session->status) { // this switch can be replaced with a simple previous_status.push(status), but it is here for readibility + case PROCESSING_QUERY: + session->previous_status.push(PROCESSING_QUERY); + break; + case PROCESSING_STMT_PREPARE: + session->previous_status.push(PROCESSING_STMT_PREPARE); + break; + case PROCESSING_STMT_EXECUTE: + session->previous_status.push(PROCESSING_STMT_EXECUTE); + break; + default: + assert(0); + break; + } + session->set_status(next_sess_status); + return true; + } + } + return false; +} + +bool MySQL_Variables::update_variable(int &_rc) { + auto idx = MySQL_Variables::var_by_session[session->status]; + updaters[idx]->update_server_variable(session, idx, _rc); +} + +bool MySQL_Variables::verify_variable(int idx) { + int rc = 0; + auto ret = updaters[idx]->verify_variables(session, idx); + if (ret) + update_variable(rc); + return ret; +} + +bool Generic_Updater::verify_variables(MySQL_Session* session, int idx) { + auto ret = session->mysql_variables->verify_generic_variable( + &session->mybe->server_myds->myconn->variables[idx].hash, + &session->mybe->server_myds->myconn->variables[idx].value, + mysql_thread___default_sql_safe_updates, + &session->client_myds->myconn->variables[idx].hash, + session->client_myds->myconn->variables[idx].value, + static_cast(MySQL_Variables::session_by_var[idx]) + ); +} + +bool Generic_Updater::update_server_variable(MySQL_Session* session, int idx, int &_rc) { + bool q = MySQL_Variables::quotes[idx]; + bool st = MySQL_Variables::set_transaction[idx]; + auto ret = session->handler_again___status_SETTING_GENERIC_VARIABLE(&_rc, Variable::set_name[idx], session->mysql_variables->server_get_value(idx), q, st); + return ret; +} diff --git a/lib/mysql_connection.cpp b/lib/mysql_connection.cpp index 41404f6f9..b443841fc 100644 --- a/lib/mysql_connection.cpp +++ b/lib/mysql_connection.cpp @@ -9,6 +9,19 @@ extern const MARIADB_CHARSET_INFO * proxysql_find_charset_nr(unsigned int nr); +const char Variable::set_name[SQL_NAME_LAST][64] = {"sql_safe_updates", "sql_select_limit", "sql_mode", "time_zone", "character_set_results", "session transaction isolation level", + "session transaction read", "session_track_gtids", "sql_auto_is_null"}; +const char Variable::proxysql_internal_session_name[SQL_NAME_LAST][64] = {"sql_safe_updates", "sql_select_limit", "sql_mode", "time_zone", "character_set_results", "isolation_level", + "transaction_read", "session_track_gtids", "sql_auto_is_null"}; + +void Variable::fill_server_internal_session(json &j, int conn_num, int idx) { + j["backends"][conn_num]["conn"][Variable::proxysql_internal_session_name[idx]] = std::string(value); +} + +void Variable::fill_client_internal_session(json &j, int idx) { + j["conn"][Variable::proxysql_internal_session_name[idx]] = value; +} + #define PROXYSQL_USE_RESULT static int @@ -202,6 +215,12 @@ MySQL_Connection::MySQL_Connection() { fd=-1; status_flags=0; last_time_used=0; + + for (auto i = 0; i < SQL_NAME_LAST; i++) { + variables[i].value = NULL; + variables[i].hash = 0; + } + options.client_flag = 0; options.compression_min_length=0; options.server_version=NULL; @@ -210,45 +229,16 @@ MySQL_Connection::MySQL_Connection() { options.no_backslash_escapes=false; options.init_connect=NULL; options.init_connect_sent=false; - options.character_set_results = NULL; - options.isolation_level = NULL; - options.tx_isolation = NULL; - options.transaction_read = NULL; - options.session_track_gtids = NULL; - options.sql_auto_is_null = NULL; - options.sql_select_limit = NULL; - options.sql_safe_updates = NULL; options.collation_connection = NULL; options.net_write_timeout = NULL; options.max_join_size = NULL; - options.isolation_level_sent = false; - options.tx_isolation_sent = false; - options.transaction_read_sent = false; - options.character_set_results_sent = false; - options.session_track_gtids_sent = false; - options.sql_auto_is_null_sent = false; - options.sql_select_limit_sent = false; - options.sql_safe_updates_sent = false; options.collation_connection_sent = false; options.net_write_timeout_sent = false; options.max_join_size_sent = false; - options.sql_mode_sent=false; options.ldap_user_variable=NULL; options.ldap_user_variable_value=NULL; options.ldap_user_variable_sent=false; options.sql_log_bin=1; // default #818 - options.sql_mode=NULL; // #509 - options.sql_mode_int=0; // #509 - options.time_zone=NULL; // #819 - options.time_zone_int=0; // #819 - options.isolation_level_int=0; - options.tx_isolation_int=0; - options.transaction_read_int=0; - options.character_set_results_int=0; - options.session_track_gtids_int=0; - options.sql_auto_is_null_int=0; - options.sql_select_limit_int=0; - options.sql_safe_updates_int=0; options.collation_connection_int=0; options.net_write_timeout_int=0; options.max_join_size_int=0; @@ -322,46 +312,14 @@ MySQL_Connection::~MySQL_Connection() { if (query.stmt) { query.stmt=NULL; } - if (options.sql_mode) { - free(options.sql_mode); - options.sql_mode=NULL; - } - if (options.time_zone) { - free(options.time_zone); - options.time_zone=NULL; - } - if (options.isolation_level) { - free(options.isolation_level); - options.isolation_level=NULL; - } - if (options.tx_isolation) { - free(options.tx_isolation); - options.tx_isolation=NULL; - } - if (options.transaction_read) { - free(options.transaction_read); - options.transaction_read=NULL; - } - if (options.character_set_results) { - free(options.character_set_results); - options.character_set_results=NULL; - } - if (options.session_track_gtids) { - free(options.session_track_gtids); - options.session_track_gtids=NULL; - } - if (options.sql_auto_is_null) { - free(options.sql_auto_is_null); - options.sql_auto_is_null=NULL; - } - if (options.sql_select_limit) { - free(options.sql_select_limit); - options.sql_select_limit=NULL; - } - if (options.sql_safe_updates) { - free(options.sql_safe_updates); - options.sql_safe_updates=NULL; + + for (auto i = 0; i < SQL_NAME_LAST; i++) { + if (variables[i].value) { + free(variables[i].value); + variables[i].value = NULL; + } } + if (options.collation_connection) { free(options.collation_connection); options.collation_connection=NULL; @@ -2187,71 +2145,19 @@ void MySQL_Connection::reset() { status_flags=0; reusable=true; options.last_set_autocommit=-1; // never sent - { // bug #1160 - options.sql_mode_int = 0; - if (options.sql_mode) { - free(options.sql_mode); - options.sql_mode = NULL; - options.sql_mode_sent = false; - - } - options.time_zone_int = 0; - if (options.time_zone) { - free(options.time_zone); - options.time_zone = NULL; - } - } + delete local_stmts; local_stmts=new MySQL_STMTs_local_v14(false); creation_time = monotonic_time(); - options.isolation_level_int = 0; - if (options.isolation_level) { - free (options.isolation_level); - options.isolation_level = NULL; - options.isolation_level_sent = false; - } - options.tx_isolation_int = 0; - if (options.tx_isolation) { - free (options.tx_isolation); - options.tx_isolation = NULL; - options.tx_isolation_sent = false; - } - options.transaction_read_int = 0; - if (options.transaction_read) { - free (options.transaction_read); - options.transaction_read = NULL; - options.transaction_read_sent = false; - } - options.character_set_results_int = 0; - if (options.character_set_results) { - free (options.character_set_results); - options.character_set_results = NULL; - options.character_set_results_sent = false; - } - options.session_track_gtids_int = 0; - if (options.session_track_gtids) { - free (options.session_track_gtids); - options.session_track_gtids = NULL; - options.session_track_gtids_sent = false; - } - options.sql_auto_is_null_int = 0; - if (options.sql_auto_is_null) { - free (options.sql_auto_is_null); - options.sql_auto_is_null = NULL; - options.sql_auto_is_null_sent = false; - } - options.sql_select_limit_int = 0; - if (options.sql_select_limit) { - free (options.sql_select_limit); - options.sql_select_limit = NULL; - options.sql_select_limit_sent = false; - } - options.sql_safe_updates_int = 0; - if (options.sql_safe_updates) { - free (options.sql_safe_updates); - options.sql_safe_updates = NULL; - options.sql_safe_updates_sent = false; + + for (auto i = 0; i < SQL_NAME_LAST; i++) { + variables[i].hash = 0; + if (variables[i].value) { + free(variables[i].value); + variables[i].value = NULL; + } } + options.collation_connection_int = 0; if (options.collation_connection) { free (options.collation_connection); diff --git a/test/tap/tests/Makefile b/test/tap/tests/Makefile index 13a87091c..a1b9122c4 100644 --- a/test/tap/tests/Makefile +++ b/test/tap/tests/Makefile @@ -12,6 +12,7 @@ PROXYSQL_PATH=../../.. PROXYSQL_IDIR=$(PROXYSQL_PATH)/include SQLITE3_DIR=$(DEPS_PATH)/sqlite3/sqlite3 +JSON_IDIR=$(DEPS_PATH)/json RE2_PATH=$(DEPS_PATH)/re2/re2 RE2_IDIR=$(RE2_PATH) @@ -63,7 +64,7 @@ EXECUTABLE=proxysql OBJ=../../../src/obj/proxysql_global.o ../../../src/obj/main.o -INCLUDEDIRS=-I../tap -I$(RE2_PATH) -I$(IDIR) -I$(JEMALLOC_IDIR) -I$(SQLITE3_DIR) -I$(LIBHTTPSERVER_IDIR) -I$(CURL_IDIR) -I$(DAEMONPATH_IDIR) -I$(MARIADB_IDIR) -I$(SSL_IDIR) +INCLUDEDIRS=-I../tap -I$(RE2_PATH) -I$(IDIR) -I$(JEMALLOC_IDIR) -I$(SQLITE3_DIR) -I$(LIBHTTPSERVER_IDIR) -I$(CURL_IDIR) -I$(DAEMONPATH_IDIR) -I$(MARIADB_IDIR) -I$(SSL_IDIR) -I$(JSON_IDIR) LDIRS=-L$(TAP_LIBDIR) -L$(LDIR) -L$(JEMALLOC_LDIR) $(LIBCONFIG_LDIR) -L$(RE2_PATH)/obj -L$(MARIADB_LDIR) -L$(DAEMONPATH_LDIR) -L$(PCRE_LDIR) -L$(MICROHTTPD_LDIR) -L$(LIBHTTPSERVER_LDIR) -L$(LIBINJECTION_LDIR) -L$(CURL_LDIR) -L$(EV_LDIR) -L$(SSL_LDIR) MYLIBS=-Wl,--export-dynamic -Wl,-Bstatic -lconfig -lproxysql -ldaemon -ljemalloc -lconfig++ -lre2 -lpcrecpp -lpcre -lmariadbclient -lhttpserver -lmicrohttpd -linjection -lcurl -lssl -lcrypto -lev -Wl,-Bdynamic -lgnutls -lpthread -lm -lz -lrt $(EXTRALINK) @@ -74,13 +75,13 @@ all: tests .PHONY: clean clean: - rm -f basic-t set_character_set-t charset_unsigned_int-t select_config_file-t sqlite3-t galera_1_timeout_count galera_2_timeout_no_count aurora test_set_character_results-t test_ps_large_result-t test_firewall-t || true + rm -f basic-t set_character_set-t charset_unsigned_int-t select_config_file-t sqlite3-t galera_1_timeout_count galera_2_timeout_no_count aurora test_set_character_results-t test_ps_large_result-t set_testing-t test_firewall-t || true OPT=-O2 -SRC=basic-t.cpp set_character_set-t.cpp charset_unsigned_int-t.cpp select_config_file-t.cpp sqlite3-t.cpp galera_1_timeout_count.cpp galera_2_timeout_no_count.cpp aurora.cpp test_set_character_results-t.cpp test_ps_large_result-t.cpp test_firewall-t.cpp +SRC=basic-t.cpp set_character_set-t.cpp charset_unsigned_int-t.cpp select_config_file-t.cpp sqlite3-t.cpp galera_1_timeout_count.cpp galera_2_timeout_no_count.cpp aurora.cpp test_set_character_results-t.cpp test_ps_large_result-t.cpp set_testing-t.cpp test_firewall-t.cpp -tests: basic-t set_character_set-t charset_unsigned_int-t select_config_file-t sqlite3-t test_set_character_results-t test_ps_large_result-t test_firewall-t +tests: basic-t set_character_set-t charset_unsigned_int-t select_config_file-t sqlite3-t test_set_character_results-t test_ps_large_result-t set_testing-t test_firewall-t testgalera: galera_1_timeout_count galera_2_timeout_no_count testaurora: aurora @@ -117,3 +118,5 @@ galera_2_timeout_no_count: galera_2_timeout_no_count.cpp $(TAP_LIBDIR)/libtap.a aurora: aurora.cpp $(TAP_LIBDIR)/libtap.a g++ -DTEST_AURORA -DDEBUG aurora.cpp ../tap/SQLite3_Server.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(OBJ) $(MYLIBS) -ltap -ldl -o aurora -DGITVERSION=\"$(GIT_VERSION)\" +set_testing-t: set_testing-t.cpp $(TAP_LIBDIR)/libtap.a + g++ set_testing-t.cpp -Wall $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(MYLIBS) -ltap -pthread -O0 -ggdb -ldl -lssl -lcrypto -o set_testing-t diff --git a/test/tap/tests/set_testing-t.cpp b/test/tap/tests/set_testing-t.cpp new file mode 100644 index 000000000..1067ecf94 --- /dev/null +++ b/test/tap/tests/set_testing-t.cpp @@ -0,0 +1,442 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "json.hpp" + +#include "tap.h" +#include "command_line.h" + + +using nlohmann::json; + +struct TestCase { + std::string command; + json expected_vars; +}; + +std::vector testCases; + +#define MAX_LINE 1024 + +int readTestCases(const std::string& fileName) { + FILE* fp = fopen(fileName.c_str(), "r"); + if (!fp) return 0; + + char buf[MAX_LINE], col1[MAX_LINE], col2[MAX_LINE]; + int n = 0; + for(;;) { + if (fgets(buf, sizeof(buf), fp) == NULL) break; + n = sscanf(buf, " \"%[^\"]\", \"%[^\"]\"", col1, col2); + if (n == 0) break; + + char *p = col2; + while(*p++) if(*p == '\'') *p = '\"'; + + json vars = json::parse(col2); + testCases.push_back({col1, vars}); + } + + fclose(fp); + return 1; +} + +unsigned long long monotonic_time() { + struct timespec ts; + //clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); // this is faster, but not precise + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((unsigned long long) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000); +} + +struct cpu_timer +{ + cpu_timer() { + begin = monotonic_time(); + } + ~cpu_timer() + { + unsigned long long end = monotonic_time(); + std::cerr << double( end - begin ) / 1000000 << " secs.\n" ; + begin=end-begin; + }; + unsigned long long begin; +}; + +int queries_per_connections=1; +unsigned int num_threads=1; +int count=0; +char *username=NULL; +char *password=NULL; +char *host=(char *)"localhost"; +int port=3306; +int multiport=1; +char *schema=(char *)"information_schema"; +int silent = 0; +int sysbench = 0; +int local=0; +int queries=0; +int uniquequeries=0; +int histograms=-1; +unsigned int g_connect_OK=0; +unsigned int g_connect_ERR=0; +unsigned int g_select_OK=0; +unsigned int g_select_ERR=0; + +unsigned int g_passed=0; +unsigned int g_failed=0; + +unsigned int status_connections = 0; +unsigned int connect_phase_completed = 0; +unsigned int query_phase_completed = 0; + +__thread int g_seed; + +inline int fastrand() { + g_seed = (214013*g_seed+2531011); + return (g_seed>>16)&0x7FFF; +} + +void parseResultJsonColumn(MYSQL_RES *result, json& j) { + if(!result) return; + MYSQL_ROW row; + + while ((row = mysql_fetch_row(result))) + j = json::parse(row[0]); +} + +void parseResult(MYSQL_RES *result, json& j) { + if(!result) return; + MYSQL_ROW row; + + while ((row = mysql_fetch_row(result))) + j[row[0]] = row[1]; +} + +void dumpResult(MYSQL_RES *result) { + if(!result) return; + MYSQL_ROW row; + + int num_fields = mysql_num_fields(result); + + while ((row = mysql_fetch_row(result))) + { + for(int i = 0; i < num_fields; i++) + { + printf("%s ", row[i] ? row[i] : "NULL"); + } + printf("\n"); + } +} + +void queryVariables(MYSQL *mysql, json& j) { + char *query = (char*)"SELECT * FROM performance_schema.session_variables WHERE variable_name IN " + " ('hostname', 'sql_log_bin', 'sql_mode', 'init_connect', 'time_zone', 'autocommit', 'sql_auto_is_null', " + " 'sql_safe_updates', 'session_track_gtids', 'max_join_size', 'net_write_timeout', 'sql_select_limit', " + " 'sql_select_limit', 'character_set_results', 'transaction_isolation', 'transaction_read_only', 'session_track_gtids', " + " 'sql_auto_is_null');"; + if (mysql_query(mysql, query)) { + if (silent==0) { + fprintf(stderr,"%s\n", mysql_error(mysql)); + } + } else { + MYSQL_RES *result = mysql_store_result(mysql); + parseResult(result, j); + + mysql_free_result(result); + __sync_fetch_and_add(&g_select_OK,1); + } +} + +void queryInternalStatus(MYSQL *mysql, json& j) { + char *query = (char*)"PROXYSQL INTERNAL SESSION"; + + if (mysql_query(mysql, query)) { + if (silent==0) { + fprintf(stderr,"%s\n", mysql_error(mysql)); + } + } else { + MYSQL_RES *result = mysql_store_result(mysql); + parseResultJsonColumn(result, j); + + mysql_free_result(result); + __sync_fetch_and_add(&g_select_OK,1); + } + + // value types in mysql and in proxysql are different + // we should convert proxysql values to mysql format to compare + for (auto& el : j.items()) { + if (el.key() == "conn") { + std::string sql_log_bin_value; + + // sql_log_bin {0|1} + if (el.value()["sql_log_bin"] == 1) { + el.value().erase("sql_log_bin"); + j["conn"]["sql_log_bin"] = "ON"; + } + else if (el.value()["sql_log_bin"] == 0) { + el.value().erase("sql_log_bin"); + j["conn"]["sql_log_bin"] = "OFF"; + } + + // autocommit {true|false} + if (!el.value()["sql_auto_is_null"].dump().compare("ON") || + !el.value()["sql_auto_is_null"].dump().compare("1") || + !el.value()["sql_auto_is_null"].dump().compare("on") || + el.value()["sql_auto_is_null"] == 1) { + el.value().erase("sql_auto_is_null"); + j["conn"]["sql_auto_is_null"] = "ON"; + } + else if (!el.value()["sql_auto_is_null"].dump().compare("OFF") || + !el.value()["sql_auto_is_null"].dump().compare("0") || + !el.value()["sql_auto_is_null"].dump().compare("off") || + el.value()["sql_auto_is_null"] == 0) { + el.value().erase("sql_auto_is_null"); + j["conn"]["sql_auto_is_null"] = "OFF"; + } + + // autocommit {true|false} + if (!el.value()["autocommit"].dump().compare("ON") || + !el.value()["autocommit"].dump().compare("1") || + !el.value()["autocommit"].dump().compare("on") || + el.value()["autocommit"] == 1) { + el.value().erase("autocommit"); + j["conn"]["autocommit"] = "ON"; + } + else if (!el.value()["autocommit"].dump().compare("OFF") || + !el.value()["autocommit"].dump().compare("0") || + !el.value()["autocommit"].dump().compare("off") || + el.value()["autocommit"] == 0) { + el.value().erase("autocommit"); + j["conn"]["autocommit"] = "OFF"; + } + + // sql_safe_updates + if (!el.value()["sql_safe_updates"].dump().compare("\"ON\"") || + !el.value()["sql_safe_updates"].dump().compare("\"1\"") || + !el.value()["sql_safe_updates"].dump().compare("\"on\"") || + el.value()["sql_safe_updates"] == 1) { + el.value().erase("sql_safe_updates"); + j["conn"]["sql_safe_updates"] = "ON"; + } + else if (!el.value()["sql_safe_updates"].dump().compare("\"OFF\"") || + !el.value()["sql_safe_updates"].dump().compare("\"0\"") || + !el.value()["sql_safe_updates"].dump().compare("\"off\"") || + el.value()["sql_safe_updates"] == 0) { + el.value().erase("sql_safe_updates"); + j["conn"]["sql_safe_updates"] = "OFF"; + } + + std::stringstream ss; + ss << 0xFFFFFFFFFFFFFFFF; + // sql_select_limit + if (!el.value()["sql_select_limit"].dump().compare("\"DEFAULT\"")) { + el.value().erase("sql_select_limit"); + j["conn"]["sql_select_limit"] = strdup(ss.str().c_str()); + } + + // transaction_isolation (level) + if (!el.value()["isolation_level"].dump().compare("\"REPEATABLE READ\"")) { + el.value().erase("isolation_level"); + j["conn"]["transaction_isolation"] = "REPEATABLE-READ"; + } + else if (!el.value()["isolation_level"].dump().compare("\"READ COMMITTED\"")) { + el.value().erase("isolation_level"); + j["conn"]["transaction_isolation"] = "READ-COMMITTED"; + } + else if (!el.value()["isolation_level"].dump().compare("\"READ UNCOMMITTED\"")) { + el.value().erase("isolation_level"); + j["conn"]["transaction_isolation"] = "READ-UNCOMMITTED"; + } + else if (!el.value()["isolation_level"].dump().compare("\"SERIALIZABLE\"")) { + el.value().erase("isolation_level"); + j["conn"]["transaction_isolation"] = "SERIALIZABLE"; + } + + // transaction_read (write|only) + if (!el.value()["transaction_read"].dump().compare("\"ONLY\"")) { + el.value().erase("transaction_read"); + j["conn"]["transaction_read_only"] = "ON"; + } + else if (!el.value()["transaction_read"].dump().compare("\"WRITE\"")) { + el.value().erase("transaction_read"); + j["conn"]["transaction_read_only"] = "OFF"; + } + + // session_track_gtids + if (!el.value()["session_track_gtids"].dump().compare("\"OFF\"")) { + el.value().erase("session_track_gtids"); + j["conn"]["session_track_gtids"] = "OFF"; + } + else if (!el.value()["session_track_gtids"].dump().compare("\"OWN_GTID\"")) { + el.value().erase("session_track_gtids"); + j["conn"]["session_track_gtids"] = "OWN_GTID"; + } + else if (!el.value()["session_track_gtids"].dump().compare("\"ALL_GTIDS\"")) { + el.value().erase("session_track_gtids"); + j["conn"]["session_track_gtids"] = "ALL_GTIDS"; + } + } + } +} + +void * my_conn_thread(void *arg) { + g_seed = time(NULL) ^ getpid() ^ pthread_self(); + unsigned int select_OK=0; + unsigned int select_ERR=0; + int i, j; + MYSQL **mysqlconns=(MYSQL **)malloc(sizeof(MYSQL *)*count); + std::vector varsperconn(count); + + if (mysqlconns==NULL) { + exit(EXIT_FAILURE); + } + for (i=0; i%s in mysql resultset was not found.\nmysql data : %s\nproxysql data: %s\ncsv data %s\n", + el.value().dump().c_str(), el.key().c_str(), mysql_vars.dump().c_str(), proxysql_vars.dump().c_str(), vars.dump().c_str()); + + if (s == proxysql_vars["conn"].end()) + fprintf(stderr, "Variable %s->%s in proxysql resultset was not found.\nmysql data : %s\nproxysql data: %s\ncsv data %s\n", + el.value().dump().c_str(), el.key().c_str(), mysql_vars.dump().c_str(), proxysql_vars.dump().c_str(), vars.dump().c_str()); + + if (k.value() != el.value() || s.value() != el.value()) { + __sync_fetch_and_add(&g_failed, 1); + testPassed = false; + fprintf(stderr, "Test failed for this case %s->%s.\n\nmysql data %s\n\n proxysql data %s\n\n csv data %s\n\n\n", + el.value().dump().c_str(), el.key().c_str(), mysql_vars.dump().c_str(), proxysql_vars.dump().c_str(), vars.dump().c_str()); + } + } + ok(testPassed, "Test passed"); + } + __sync_fetch_and_add(&query_phase_completed,1); + + return NULL; +} + +int main(int argc, char *argv[]) { + CommandLine cl; + std::string fileName("./tests/set_testing-t.csv"); + + if(cl.getEnv()) + return exit_status(); + + num_threads = 10; + queries = 1000; + queries_per_connections = 10; + count = 10; + username = cl.username; + password = cl.password; + host = cl.host; + port = cl.port; + + plan(queries * num_threads); + if (!readTestCases(fileName)) { + fprintf(stderr, "Cannot read %s\n", fileName.c_str()); + return exit_status(); + } + + if (strcmp(host,"localhost")==0) { + local = 1; + } + if (uniquequeries == 0) { + if (queries) uniquequeries=queries; + } + if (uniquequeries) { + uniquequeries=(int)sqrt(uniquequeries); + } + mysql_library_init(0, NULL, NULL); + + pthread_t *thi=(pthread_t *)malloc(sizeof(pthread_t)*num_threads); + if (thi==NULL) + return exit_status(); + + for (unsigned int i=0; i