diff --git a/include/MySQL_Variables.h b/include/MySQL_Variables.h index 6633ce243..1c25587af 100644 --- a/include/MySQL_Variables.h +++ b/include/MySQL_Variables.h @@ -46,6 +46,8 @@ public: bool verify_variable(MySQL_Session* session, int idx) const; bool update_variable(MySQL_Session* session, session_status status, int &_rc); bool on_connect_to_backend(MySQL_Connection *myconn); + bool parse_variable_boolean(MySQL_Session *sess, int idx, string &value1, bool& exit_after_SetParse, bool* lock_hostgroup); + bool parse_variable_number(MySQL_Session *sess, int idx, string &value1, bool& exit_after_SetParse, bool* lock_hostgroup); }; #endif // #ifndef MYSQL_VARIABLES_H diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h index d8c0f1c14..233cc5981 100644 --- a/include/proxysql_structs.h +++ b/include/proxysql_structs.h @@ -206,6 +206,8 @@ typedef struct { bool quote; // if the variable needs to be quoted bool set_transaction; // if related to SET TRANSACTION statement . if false , it will be execute "SET varname = varvalue" . If true, "SET varname varvalue" bool special_handling; // if true, some special handling is required + bool is_number; // if true, the variable is a number. Special cases should be checked + bool is_bool; // if true, the variable is a boolean. Special cases should be checked char * set_variable_name; // what variable name (or string) will be used when setting it to backend char * internal_variable_name; // variable name as displayed in admin , WITHOUT "default_" char * default_value; // default value @@ -969,29 +971,45 @@ extern __thread unsigned int g_seed; // field_3: if the variable needs to be quoted // field_4: if related to SET TRANSACTION statement . if false , it will be execute "SET varname = varvalue" . If true, "SET varname varvalue" // field_5: if true, some special handling is required -// field_6: what variable name (or string) will be used when setting it to backend -// field_7: variable name as displayed in admin , WITHOUT "default_" -// field_8: default value +// field_6: if true, the variable is a number. Special cases should be checked +// field_7: if true, the variable is a boolean. Special cases should be checked +// field_8: what variable name (or string) will be used when setting it to backend +// field_9: variable name as displayed in admin , WITHOUT "default_" +// field_10: default value +/* +typedef struct { + enum variable_name idx; // index number + enum session_status status; // what status should be changed after setting this variables + bool quote; // if the variable needs to be quoted + bool set_transaction; // if related to SET TRANSACTION statement . if false , it will be execute "SET varname = varvalue" . If true, "SET varname varvalue" + bool special_handling; // if true, some special handling is required + bool is_number; // if true, the variable is a number. Special cases should be checked + bool is_bool; // if true, the variable is a boolean. Special cases should be checked + char * set_variable_name; // what variable name (or string) will be used when setting it to backend + char * internal_variable_name; // variable name as displayed in admin , WITHOUT "default_" + char * default_value; // default value +} mysql_variable_st; +*/ mysql_variable_st mysql_tracked_variables[] { - { SQL_CHARACTER_SET, SETTING_CHARSET, false, true, false, (char *)"CHARSET", (char *)"CHARSET", (char *)"UTF8" } , // should be before SQL_CHARACTER_SET_RESULTS - { SQL_CHARACTER_ACTION, NONE, false, false, false, (char *)"action", (char *)"action", (char *)"1" } , - { SQL_SET_NAMES, SETTING_SET_NAMES,false, false, false, (char *)"names", (char *)"names", (char *)"DEFAULT" } , - { SQL_SAFE_UPDATES, SETTING_VARIABLE, true, false, true, (char *)"sql_safe_updates", (char *)"sql_safe_updates", (char *)"OFF" } , - { SQL_SELECT_LIMIT, SETTING_VARIABLE, false, false, true, (char *)"sql_select_limit", (char *)"sql_select_limit", (char *)"DEFAULT" } , - { SQL_SQL_MODE, SETTING_VARIABLE, true, false, true, (char *)"sql_mode" , (char *)"sql_mode" , (char *)"" } , - { SQL_TIME_ZONE, SETTING_VARIABLE, true, false, true, (char *)"time_zone", (char *)"time_zone", (char *)"SYSTEM" } , - { SQL_CHARACTER_SET_RESULTS, SETTING_VARIABLE, false, false, true, (char *)"character_set_results", (char *)"character_set_results", (char *)"UTF8" } , - { SQL_CHARACTER_SET_CONNECTION, SETTING_VARIABLE, false, false, true, (char *)"character_set_connection", (char *)"character_set_connection", (char *)"UTF8" } , - { SQL_CHARACTER_SET_CLIENT, SETTING_VARIABLE, false, false, true, (char *)"character_set_client", (char *)"character_set_client", (char *)"UTF8" } , - { SQL_CHARACTER_SET_DATABASE, SETTING_VARIABLE, false, false, true, (char *)"character_set_database", (char *)"character_set_database", (char *)"UTF8" } , - { SQL_ISOLATION_LEVEL, SETTING_ISOLATION_LEVEL, false, true, true, (char *)"SESSION TRANSACTION ISOLATION LEVEL", (char *)"isolation_level", (char *)"READ COMMITTED" } , - { SQL_TRANSACTION_READ, SETTING_TRANSACTION_READ, false, true, true, (char *)"SESSION TRANSACTION READ", (char *)"transaction_read", (char *)"WRITE" } , - { SQL_SQL_AUTO_IS_NULL, SETTING_VARIABLE, true, false, true, (char *)"sql_auto_is_null", (char *)"sql_auto_is_null", (char *)"OFF" } , - { SQL_COLLATION_CONNECTION, SETTING_VARIABLE, true, false, true, (char *)"collation_connection", (char *)"collation_connection", (char *)"utf8_general_ci" } , - { SQL_NET_WRITE_TIMEOUT, SETTING_VARIABLE, false, false, true, (char *)"net_write_timeout", (char *)"net_write_timeout", (char *)"60" } , - { SQL_MAX_JOIN_SIZE, SETTING_VARIABLE, false, false, true, (char *)"max_join_size", (char *)"max_join_size", (char *)"18446744073709551615" } , - { SQL_LOG_BIN, SETTING_VARIABLE, false, false, true, (char *)"sql_log_bin", (char *)"sql_log_bin", (char *)"1" } , - { SQL_WSREP_SYNC_WAIT, SETTING_VARIABLE, false, false, true, (char *)"wsrep_sync_wait", (char *)"wsrep_sync_wait", (char *)"0" } , + { SQL_CHARACTER_SET, SETTING_CHARSET, false, true, false, false, false, (char *)"CHARSET", (char *)"CHARSET", (char *)"UTF8" } , // should be before SQL_CHARACTER_SET_RESULTS + { SQL_CHARACTER_ACTION, NONE, false, false, false, false, false, (char *)"action", (char *)"action", (char *)"1" } , + { SQL_SET_NAMES, SETTING_SET_NAMES, false, false, false, false, false, (char *)"names", (char *)"names", (char *)"DEFAULT" } , + { SQL_SAFE_UPDATES, SETTING_VARIABLE, true, false, true, false, true, (char *)"sql_safe_updates", (char *)"sql_safe_updates", (char *)"OFF" } , + { SQL_SELECT_LIMIT, SETTING_VARIABLE, false, false, true, true, false, (char *)"sql_select_limit", (char *)"sql_select_limit", (char *)"DEFAULT" } , + { SQL_SQL_MODE, SETTING_VARIABLE, true, false, true, false, false, (char *)"sql_mode" , (char *)"sql_mode" , (char *)"" } , + { SQL_TIME_ZONE, SETTING_VARIABLE, true, false, true, false, false, (char *)"time_zone", (char *)"time_zone", (char *)"SYSTEM" } , + { SQL_CHARACTER_SET_RESULTS, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_results", (char *)"character_set_results", (char *)"UTF8" } , + { SQL_CHARACTER_SET_CONNECTION, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_connection", (char *)"character_set_connection", (char *)"UTF8" } , + { SQL_CHARACTER_SET_CLIENT, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_client", (char *)"character_set_client", (char *)"UTF8" } , + { SQL_CHARACTER_SET_DATABASE, SETTING_VARIABLE, false, false, true, false, false, (char *)"character_set_database", (char *)"character_set_database", (char *)"UTF8" } , + { SQL_ISOLATION_LEVEL, SETTING_ISOLATION_LEVEL, false, true, true, false, false, (char *)"SESSION TRANSACTION ISOLATION LEVEL", (char *)"isolation_level", (char *)"READ COMMITTED" } , + { SQL_TRANSACTION_READ, SETTING_TRANSACTION_READ, false, true, true, false, false, (char *)"SESSION TRANSACTION READ", (char *)"transaction_read", (char *)"WRITE" } , + { SQL_SQL_AUTO_IS_NULL, SETTING_VARIABLE, true, false, true, false, true, (char *)"sql_auto_is_null", (char *)"sql_auto_is_null", (char *)"OFF" } , + { SQL_COLLATION_CONNECTION, SETTING_VARIABLE, true, false, true, false, false, (char *)"collation_connection", (char *)"collation_connection", (char *)"utf8_general_ci" } , + { SQL_NET_WRITE_TIMEOUT, SETTING_VARIABLE, false, false, true, true, false, (char *)"net_write_timeout", (char *)"net_write_timeout", (char *)"60" } , + { SQL_MAX_JOIN_SIZE, SETTING_VARIABLE, false, false, true, true, false, (char *)"max_join_size", (char *)"max_join_size", (char *)"18446744073709551615" } , + { SQL_LOG_BIN, SETTING_VARIABLE, false, false, true, false, false, (char *)"sql_log_bin", (char *)"sql_log_bin", (char *)"1" } , + { SQL_WSREP_SYNC_WAIT, SETTING_VARIABLE, false, false, true, false, false, (char *)"wsrep_sync_wait", (char *)"wsrep_sync_wait", (char *)"0" } , }; #else extern mysql_variable_st mysql_tracked_variables[]; diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index af5952c5d..8c1e9412b 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -5036,54 +5036,36 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C unable_to_parse_set_statement(lock_hostgroup); return false; } + // the following two blocks of code will be simplified later } else if ((var == "sql_auto_is_null") || (var == "sql_safe_updates")) { - std::string value1 = *values; - proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET %s value %s\n", var.c_str(), value1.c_str()); - int __tmp_value = -1; - if ( - (strcasecmp(value1.c_str(),(char *)"0")==0) || - (strcasecmp(value1.c_str(),(char *)"false")==0) || - (strcasecmp(value1.c_str(),(char *)"off")==0) - ) { - __tmp_value = 0; - } else { - if ( - (strcasecmp(value1.c_str(),(char *)"1")==0) || - (strcasecmp(value1.c_str(),(char *)"true")==0) || - (strcasecmp(value1.c_str(),(char *)"on")==0) - ) { - __tmp_value = 1; - } - } - if (__tmp_value >= 0) { - proxy_debug(PROXY_DEBUG_MYSQL_COM, 7, "Processing SET %s value %s\n", var.c_str(), value1.c_str()); - uint32_t var_value_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); - int idx = SQL_NAME_LAST; - for (int i = 0 ; i < SQL_NAME_LAST ; i++) { - if (!strcmp(var.c_str(), mysql_tracked_variables[i].set_variable_name)) { + int idx = SQL_NAME_LAST; + for (int i = 0 ; i < SQL_NAME_LAST ; i++) { + if (mysql_tracked_variables[i].is_bool) { + if (!strcasecmp(var.c_str(), mysql_tracked_variables[i].set_variable_name)) { idx = mysql_tracked_variables[i].idx; break; } } - if (idx == SQL_NAME_LAST) { - proxy_error("Variable %s not found in mysql_tracked_variables[]\n", var.c_str()); - unable_to_parse_set_statement(lock_hostgroup); + } + if (idx != SQL_NAME_LAST) { + if (mysql_variables.parse_variable_boolean(this,idx, *values, exit_after_SetParse, lock_hostgroup)==false) { return false; } - if (mysql_variables.client_get_hash(this, idx) != var_value_int) { - if (__tmp_value == 0) { - if (!mysql_variables.client_set_value(this, idx, "OFF")) - return false; - } else { - if (!mysql_variables.client_set_value(this, idx, "ON")) - return false; + } + } else if ( (var == "sql_select_limit") || (var == "net_write_timeout") || (var == "max_join_size") ) { + int idx = SQL_NAME_LAST; + for (int i = 0 ; i < SQL_NAME_LAST ; i++) { + if (mysql_tracked_variables[i].is_number) { + if (!strcasecmp(var.c_str(), mysql_tracked_variables[i].set_variable_name)) { + idx = mysql_tracked_variables[i].idx; + break; } - proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection %s to %s\n", var.c_str(), value1.c_str()); } - exit_after_SetParse = true; - } else { - unable_to_parse_set_statement(lock_hostgroup); - return false; + } + if (idx != SQL_NAME_LAST) { + if (mysql_variables.parse_variable_number(this,idx, *values, exit_after_SetParse, lock_hostgroup)==false) { + return false; + } } } else if (var == "autocommit") { std::string value1 = *values; @@ -5175,48 +5157,6 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C unable_to_parse_set_statement(lock_hostgroup); return false; } - } else if ( (var == "sql_select_limit") || (var == "net_write_timeout") || (var == "max_join_size") ) { - std::string value1 = *values; - int vl = strlen(value1.c_str()); - const char *v = value1.c_str(); - bool only_digit_chars = true; - for (int i=0; i + +static inline char is_digit(char c) { + if(c >= '0' && c <= '9') + return 1; + return 0; +} + + verify_var MySQL_Variables::verifiers[SQL_NAME_LAST]; update_var MySQL_Variables::updaters[SQL_NAME_LAST]; @@ -452,3 +460,77 @@ bool logbin_update_server_variable(MySQL_Session* session, int idx, int &_rc) { return session->handler_again___status_SETTING_SQL_LOG_BIN(&_rc); } + +bool MySQL_Variables::parse_variable_boolean(MySQL_Session *sess, int idx, string& value1, bool& exit_after_SetParse, bool * lock_hostgroup) { + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET %s value %s\n", mysql_tracked_variables[idx].set_variable_name, value1.c_str()); + int __tmp_value = -1; + if ( + (strcasecmp(value1.c_str(),(char *)"0")==0) || + (strcasecmp(value1.c_str(),(char *)"false")==0) || + (strcasecmp(value1.c_str(),(char *)"off")==0) + ) { + __tmp_value = 0; + } else { + if ( + (strcasecmp(value1.c_str(),(char *)"1")==0) || + (strcasecmp(value1.c_str(),(char *)"true")==0) || + (strcasecmp(value1.c_str(),(char *)"on")==0) + ) { + __tmp_value = 1; + } + } + + if (__tmp_value >= 0) { + proxy_debug(PROXY_DEBUG_MYSQL_COM, 7, "Processing SET %s value %s\n", mysql_tracked_variables[idx].set_variable_name, value1.c_str()); + uint32_t var_value_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); + if (mysql_variables.client_get_hash(sess, idx) != var_value_int) { + if (__tmp_value == 0) { + if (!mysql_variables.client_set_value(sess, idx, "OFF")) + return false; + } else { + if (!mysql_variables.client_set_value(sess, idx, "ON")) + return false; + } + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection %s to %s\n", mysql_tracked_variables[idx].set_variable_name, value1.c_str()); + } + exit_after_SetParse = true; + } else { + sess->unable_to_parse_set_statement(lock_hostgroup); + return false; + } + return true; +} + + + +bool MySQL_Variables::parse_variable_number(MySQL_Session *sess, int idx, string& value1, bool& exit_after_SetParse, bool * lock_hostgroup) { + int vl = strlen(value1.c_str()); + const char *v = value1.c_str(); + bool only_digit_chars = true; + for (int i=0; iunable_to_parse_set_statement(lock_hostgroup); + return false; + } + return true; +}