#include "MySQL_Variables.h" #include "proxysql.h" #include "MySQL_Session.h" #include "MySQL_Data_Stream.h" #ifndef SPOOKYV2 #include "SpookyV2.h" #define SPOOKYV2 #endif #include #include "mysqld_error.h" static inline char is_digit(char c) { if(c >= '0' && c <= '9') return 1; return 0; } var_track_err_st perm_track_errs[] { // ERROR 1210 (HY000): Variable not supported in combination with Galera: // - Changed by MySQL, previously 'ER_UNKNOWN_SYSTEM_VARIABLE' { ER_WRONG_ARGUMENTS, "sql_generate_invisible_primary_key" } }; bool is_perm_track_err(int err, const char* varname) { const size_t count = sizeof(perm_track_errs) / sizeof(var_track_err_st); for (size_t i = 0; i < count; i++) { if (perm_track_errs[i].err == err && (strcasecmp(varname, perm_track_errs[i].name) == 0)) { return true; } } return false; } #include "proxysql_find_charset.h" verify_var MySQL_Variables::verifiers[SQL_NAME_LAST_HIGH_WM]; update_var MySQL_Variables::updaters[SQL_NAME_LAST_HIGH_WM]; MySQL_Variables::MySQL_Variables() { // add here all the variables we want proxysql to recognize, but ignore ignore_vars.push_back("interactive_timeout"); ignore_vars.push_back("wait_timeout"); ignore_vars.push_back("net_read_timeout"); ignore_vars.push_back("net_write_timeout"); ignore_vars.push_back("net_buffer_length"); ignore_vars.push_back("read_buffer_size"); ignore_vars.push_back("read_rnd_buffer_size"); // NOTE: This variable has been temporarily ignored. Check issues #3442 and #3441. ignore_vars.push_back("session_track_schema"); // NOTE: This variable has been temporarily ignored. Check issues #4839 ignore_vars.push_back("session_track_system_variables"); variables_regexp = ""; for (auto i = 0; i < SQL_NAME_LAST_HIGH_WM; i++) { // we initialized all the internal_variable_name if set to NULL if (mysql_tracked_variables[i].internal_variable_name == NULL) { mysql_tracked_variables[i].internal_variable_name = mysql_tracked_variables[i].set_variable_name; } } /* NOTE: make special ATTENTION that the order in mysql_variable_name and mysql_tracked_variables[] is THE SAME NOTE: MySQL_Variables::MySQL_Variables() has a built-in check to make sure that the order is correct, and that variables are in alphabetical order */ for (int i = SQL_NAME_LAST_LOW_WM; i < SQL_NAME_LAST_HIGH_WM; i++) { assert(i == mysql_tracked_variables[i].idx); if (i > SQL_NAME_LAST_LOW_WM+1) { assert(strcmp(mysql_tracked_variables[i].set_variable_name, mysql_tracked_variables[i-1].set_variable_name) > 0); } } for (auto i = 0; i < SQL_NAME_LAST_HIGH_WM; i++) { if (i == SQL_CHARACTER_SET || i == SQL_CHARACTER_ACTION || i == SQL_SET_NAMES) { MySQL_Variables::updaters[i] = NULL; MySQL_Variables::verifiers[i] = NULL; } else if (i == SQL_SQL_LOG_BIN) { MySQL_Variables::verifiers[i] = verify_server_variable; MySQL_Variables::updaters[i] = logbin_update_server_variable; } else { MySQL_Variables::verifiers[i] = verify_server_variable; MySQL_Variables::updaters[i] = update_server_variable; } if (mysql_tracked_variables[i].status == SETTING_VARIABLE) { variables_regexp += mysql_tracked_variables[i].set_variable_name; variables_regexp += "|"; } } for (std::vector::iterator it=ignore_vars.begin(); it != ignore_vars.end(); it++) { variables_regexp += *it; variables_regexp += "|"; } } MySQL_Variables::~MySQL_Variables() {} bool MySQL_Variables::client_set_hash_and_value(MySQL_Session* session, int idx, const std::string& value, uint32_t hash) { if (!session || !session->client_myds || !session->client_myds->myconn) { proxy_warning("Session validation failed\n"); return false; } session->client_myds->myconn->var_hash[idx] = hash; 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.c_str()); return true; } void MySQL_Variables::client_reset_value(MySQL_Session* session, int idx) { if (!session || !session->client_myds || !session->client_myds->myconn) { proxy_warning("Session validation failed\n"); return; } MySQL_Connection *client_conn = session->client_myds->myconn; if (client_conn->var_hash[idx] != 0) { client_conn->var_hash[idx] = 0; if (client_conn->variables[idx].value) { free(client_conn->variables[idx].value); client_conn->variables[idx].value = NULL; } // we now regererate dynamic_variables_idx client_conn->reorder_dynamic_variables_idx(); } } void MySQL_Variables::server_set_hash_and_value(MySQL_Session* session, int idx, const char* value, uint32_t hash) { if (!session || !session->mybe || !session->mybe->server_myds || !session->mybe->server_myds->myconn || !value) { proxy_warning("Session validation failed\n"); return; } session->mybe->server_myds->myconn->var_hash[idx] = hash; 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); } /** * @brief Set the supplied value for the session variable specified by the supplied * index into the supplied client session. * * @details There are two session variables which require special handling: * - 'SET NAMES' * - 'SET CHARACTER SET' * * For the second case 'SET CHARACTER SET' we forget about the values for: * - 'SQL_CHARACTER_SET_CONNECTION' * - 'SQL_COLLATION_CONNECTION' * * This is done because 'character_set_database' is not known when the set happens and * because we work under the assumption that if a client request 'SET CHARACTER SET' * doesn't require a specific 'collation_connection' and 'character_set_connection". * Furthermore, 'character_set_database' is deprecated since MySQL 5.7 and will only * be usable as an immutable session variable in the future. For reference see: * * - 'https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_character_set_database * * Due to this, *it's expected behavior* to see that a connection that sets 'SET CHARACTER SET' * has a variant 'collation_connection' and 'character_set_connection' depending on the * backend connection that is retrieved from the connection pool. If the 'collation_connection' * and 'character_set_connection' variables are relevant and should never change, * 'SET NAMES' should be used. * * @param session The client session which variable value is going to be modified. * @param idx The index of the session variable to modify. * @param value The session variable value to be set. * * @return 'true' in case of success, 'false' otherwise. */ bool MySQL_Variables::client_set_value(MySQL_Session* session, int idx, const std::string& value) { if (!session || !session->client_myds || !session->client_myds->myconn) { proxy_warning("Session validation failed\n"); return false; } /* Process SET NAMES and SET CHARSET commands * The character_set_client, character_set_results, character_set_connection variables are set here * During multiplexing/query execution these values will be used to set corresponding backend variables * The charset used in SET NAMES and SET CHARSET is not used in setting backend chrsets */ switch (idx) { case SQL_CHARACTER_ACTION: // SET NAMES command from client if (value == "1") { if (mysql_variables.client_get_value(session, SQL_CHARACTER_SET)) { const char* value = mysql_variables.client_get_value(session, SQL_CHARACTER_SET); uint32_t hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET); mysql_variables.client_set_hash_and_value(session, SQL_CHARACTER_SET_RESULTS, value, hash); mysql_variables.client_set_hash_and_value(session, SQL_CHARACTER_SET_CLIENT, value, hash); mysql_variables.client_set_hash_and_value(session, SQL_CHARACTER_SET_CONNECTION, value, hash); mysql_variables.client_set_hash_and_value(session, SQL_COLLATION_CONNECTION, value, hash); } } // SET CHARSET command from client else if (value == "2") { if (mysql_variables.client_get_value(session, SQL_CHARACTER_SET)) { const char* value = mysql_variables.client_get_value(session, SQL_CHARACTER_SET); uint32_t hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET); mysql_variables.client_set_hash_and_value(session, SQL_CHARACTER_SET_RESULTS, value, hash); mysql_variables.client_set_hash_and_value(session, SQL_CHARACTER_SET_CLIENT, value, hash); // Setting connection and collation connection to NULL // because we do not know database character set mysql_variables.client_set_hash_and_value(session, SQL_CHARACTER_SET_CONNECTION, "", 0); mysql_variables.client_set_hash_and_value(session, SQL_COLLATION_CONNECTION, "", 0); } } } session->client_myds->myconn->var_hash[idx] = SpookyHash::Hash32(value.c_str(),strlen(value.c_str()),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.c_str()); // we now regererate dynamic_variables_idx session->client_myds->myconn->reorder_dynamic_variables_idx(); return true; } const char* MySQL_Variables::client_get_value(MySQL_Session* session, int idx) const { assert(session); assert(session->client_myds); assert(session->client_myds->myconn); return session->client_myds->myconn->variables[idx].value; } uint32_t MySQL_Variables::client_get_hash(MySQL_Session* session, int idx) const { assert(session); assert(session->client_myds); assert(session->client_myds->myconn); return session->client_myds->myconn->var_hash[idx]; } void MySQL_Variables::server_set_value(MySQL_Session* session, int idx, const char* value) { assert(session); assert(session->mybe); assert(session->mybe->server_myds); assert(session->mybe->server_myds->myconn); if (!value) return; // FIXME: I am not sure about this implementation . If value == NULL , show the variable be reset? session->mybe->server_myds->myconn->var_hash[idx] = 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); // we now regererate dynamic_variables_idx session->mybe->server_myds->myconn->reorder_dynamic_variables_idx(); } void MySQL_Variables::server_reset_value(MySQL_Session* session, int idx) { assert(session); assert(session->mybe); assert(session->mybe->server_myds); assert(session->mybe->server_myds->myconn); MySQL_Connection *backend_conn = session->mybe->server_myds->myconn; if (backend_conn->var_hash[idx] != 0) { backend_conn->var_hash[idx] = 0; if (backend_conn->variables[idx].value) { free(backend_conn->variables[idx].value); backend_conn->variables[idx].value = NULL; } // we now regererate dynamic_variables_idx backend_conn->reorder_dynamic_variables_idx(); } } const char* MySQL_Variables::server_get_value(MySQL_Session* session, int idx) const { assert(session); assert(session->mybe); assert(session->mybe->server_myds); assert(session->mybe->server_myds->myconn); return session->mybe->server_myds->myconn->variables[idx].value; } uint32_t MySQL_Variables::server_get_hash(MySQL_Session* session, int idx) const { assert(session); assert(session->mybe); assert(session->mybe->server_myds); assert(session->mybe->server_myds->myconn); return session->mybe->server_myds->myconn->var_hash[idx]; } bool MySQL_Variables::update_variable(MySQL_Session* session, session_status status, int &_rc) { int idx = SQL_NAME_LAST_HIGH_WM; if (session->status == SETTING_VARIABLE) { // if status is SETTING_VARIABLE , what variable needs to be changed is defined in changing_variable_idx idx = session->changing_variable_idx; } else { for (int i=0; iclient_myds->myconn->var_hash[idx]; auto server_hash = session->mybe->server_myds->myconn->var_hash[idx]; if (client_hash && client_hash != server_hash) { ret = verifiers[idx](session, idx, client_hash, server_hash); } } return ret; } bool validate_charset(MySQL_Session* session, int idx, int &_rc) { if (idx == SQL_CHARACTER_SET || idx == SQL_CHARACTER_SET_CLIENT || idx == SQL_CHARACTER_SET_RESULTS || idx == SQL_CHARACTER_SET_CONNECTION || idx == SQL_CHARACTER_SET_DATABASE || idx == SQL_COLLATION_CONNECTION) { MySQL_Data_Stream *myds = session->mybe->server_myds; MySQL_Connection *myconn = myds->myconn; char msg[128]; const MARIADB_CHARSET_INFO *ci = NULL; const char* replace_collation = NULL; const char* not_supported_collation = NULL; unsigned int replace_collation_nr = 0; std::stringstream ss; int charset = atoi(mysql_variables.client_get_value(session, idx)); if (charset >= 255 && myconn->mysql->server_version[0] != '8') { switch(mysql_thread___handle_unknown_charset) { case HANDLE_UNKNOWN_CHARSET__DISCONNECT_CLIENT: snprintf(msg,sizeof(msg),"Can't initialize character set %s", mysql_variables.client_get_value(session, idx)); proxy_error("Can't initialize character set on %s, %d: Error %d (%s). Closing client connection %s:%d.\n", myconn->parent->address, myconn->parent->port, 2019, msg, session->client_myds->addr.addr, session->client_myds->addr.port); myds->destroy_MySQL_Connection_From_Pool(false); myds->fd=0; _rc=-1; return false; case HANDLE_UNKNOWN_CHARSET__REPLACE_WITH_DEFAULT_VERBOSE: ci = proxysql_find_charset_nr(charset); if (!ci) { // LCOV_EXCL_START proxy_error("Cannot find character set [%s]\n", mysql_variables.client_get_value(session, idx)); assert(0); // LCOV_EXCL_STOP } not_supported_collation = ci->name; if (idx == SQL_COLLATION_CONNECTION) { ci = proxysql_find_charset_collate(mysql_thread___default_variables[idx]); } else { if (mysql_thread___default_variables[idx]) { ci = proxysql_find_charset_name(mysql_thread___default_variables[idx]); } else { ci = proxysql_find_charset_name(mysql_thread___default_variables[SQL_CHARACTER_SET]); } } if (!ci) { // LCOV_EXCL_START proxy_error("Cannot find character set [%s]\n", mysql_thread___default_variables[idx]); assert(0); // LCOV_EXCL_STOP } replace_collation = ci->name; replace_collation_nr = ci->nr; proxy_warning("Server doesn't support collation (%s) %s. Replacing it with the configured default (%d) %s. Client %s:%d\n", mysql_variables.client_get_value(session, idx), not_supported_collation, replace_collation_nr, replace_collation, session->client_myds->addr.addr, session->client_myds->addr.port); ss << replace_collation_nr; mysql_variables.client_set_value(session, idx, ss.str()); _rc=0; return true; case HANDLE_UNKNOWN_CHARSET__REPLACE_WITH_DEFAULT: if (idx == SQL_COLLATION_CONNECTION) { ci = proxysql_find_charset_collate(mysql_thread___default_variables[idx]); } else { if (mysql_thread___default_variables[idx]) { ci = proxysql_find_charset_name(mysql_thread___default_variables[idx]); } else { ci = proxysql_find_charset_name(mysql_thread___default_variables[SQL_CHARACTER_SET]); } } if (!ci) { // LCOV_EXCL_START proxy_error("Cannot filnd charset [%s]\n", mysql_thread___default_variables[idx]); assert(0); // LCOV_EXCL_STOP } replace_collation_nr = ci->nr; ss << replace_collation_nr; mysql_variables.client_set_value(session, idx, ss.str()); _rc=0; return true; default: proxy_error("Wrong configuration of the handle_unknown_charset\n"); _rc=-1; return false; } } } _rc=0; return true; } bool update_server_variable(MySQL_Session* session, int idx, int &_rc) { bool no_quote = true; if (mysql_tracked_variables[idx].quote) no_quote = false; bool st = mysql_tracked_variables[idx].set_transaction; const char * set_var_name = mysql_tracked_variables[idx].set_variable_name; bool ret = false; /* Validating that charset is less than 255 for mysqld version <8.0 */ if (!validate_charset(session, idx, _rc)) { return false; } /* character set variables store collation id in the char* string, but we set character_set_% command * uses character set name or collation name. This branch convert collation id to character set name * or collation name for further execution on backend */ if (idx==SQL_CHARACTER_SET_RESULTS) { const MARIADB_CHARSET_INFO *ci = NULL; ci = proxysql_find_charset_nr(atoi(mysql_variables.client_get_value(session, SQL_CHARACTER_SET_RESULTS))); if (!ci) { if (!strcmp(mysql_variables.client_get_value(session, SQL_CHARACTER_SET_RESULTS), "NULL")) { mysql_variables.server_set_value(session, idx, mysql_variables.client_get_value(session, idx)); ret = session->handler_again___status_SETTING_GENERIC_VARIABLE(&_rc, set_var_name, "NULL", no_quote, st); } else if (!strcmp(mysql_variables.client_get_value(session, SQL_CHARACTER_SET_RESULTS), "binary")) { mysql_variables.server_set_value(session, idx, mysql_variables.client_get_value(session, idx)); ret = session->handler_again___status_SETTING_GENERIC_VARIABLE(&_rc, set_var_name, "binary", no_quote, st); } } else { mysql_variables.server_set_value(session, idx, mysql_variables.client_get_value(session, idx)); ret = session->handler_again___status_SETTING_GENERIC_VARIABLE(&_rc, set_var_name, ci->csname, no_quote, st); } } else if (idx==SQL_COLLATION_CONNECTION) { const MARIADB_CHARSET_INFO *ci = NULL; ci = proxysql_find_charset_nr(atoi(mysql_variables.client_get_value(session, SQL_COLLATION_CONNECTION))); if (ci) { std::stringstream ss; ss << ci->nr; mysql_variables.server_set_value(session, idx, mysql_variables.client_get_value(session, idx)); ret = session->handler_again___status_SETTING_GENERIC_VARIABLE(&_rc, set_var_name, ci->name, no_quote, st); } } else if (idx==SQL_CHARACTER_SET_CONNECTION) { const MARIADB_CHARSET_INFO *ci = NULL; ci = proxysql_find_charset_nr(atoi(mysql_variables.client_get_value(session, SQL_CHARACTER_SET_CONNECTION))); if (ci) { unsigned int nr = ci->nr; std::stringstream ss; ss << nr; mysql_variables.server_set_value(session, idx, mysql_variables.client_get_value(session, idx)); ret = session->handler_again___status_SETTING_GENERIC_VARIABLE(&_rc, set_var_name, ci->csname, no_quote, st); } } else if (idx==SQL_CHARACTER_SET_CLIENT || idx==SQL_CHARACTER_SET_DATABASE) { const MARIADB_CHARSET_INFO *ci = NULL; ci = proxysql_find_charset_nr(atoi(mysql_variables.client_get_value(session, idx))); std::stringstream ss; ss << ci->nr; mysql_variables.server_set_value(session, idx, mysql_variables.client_get_value(session, idx)); ret = session->handler_again___status_SETTING_GENERIC_VARIABLE(&_rc, set_var_name, ci->csname, no_quote, st); } else { mysql_variables.server_set_value(session, idx, mysql_variables.client_get_value(session, idx)); ret = session->handler_again___status_SETTING_GENERIC_VARIABLE(&_rc, set_var_name, mysql_variables.server_get_value(session, idx), no_quote, st); } return ret; } bool verify_set_names(MySQL_Session* session) { uint32_t client_charset_hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET_CLIENT); if (client_charset_hash == 0) return false; uint32_t results_charset_hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET_RESULTS); if (client_charset_hash != results_charset_hash) return false; uint32_t connection_charset_hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET_CONNECTION); if (client_charset_hash != connection_charset_hash) return false; uint32_t collation_hash = mysql_variables.client_get_hash(session, SQL_COLLATION_CONNECTION); if (client_charset_hash != collation_hash) return false; if (client_charset_hash != mysql_variables.server_get_hash(session, SQL_CHARACTER_SET_CLIENT) || results_charset_hash != mysql_variables.server_get_hash(session, SQL_CHARACTER_SET_RESULTS) || connection_charset_hash != mysql_variables.server_get_hash(session, SQL_CHARACTER_SET_CONNECTION) || collation_hash != mysql_variables.server_get_hash(session, SQL_COLLATION_CONNECTION)) { 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: // LCOV_EXCL_START proxy_error("Wrong status %d\n", session->status); assert(0); break; // LCOV_EXCL_STOP } session->set_status(SETTING_SET_NAMES); uint32_t hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET_CLIENT); const char* value = mysql_variables.client_get_value(session, SQL_CHARACTER_SET_CLIENT); mysql_variables.server_set_hash_and_value(session, SQL_CHARACTER_SET_CLIENT, value, hash); mysql_variables.server_set_hash_and_value(session, SQL_CHARACTER_SET_RESULTS, value, hash); mysql_variables.server_set_hash_and_value(session, SQL_CHARACTER_SET_CONNECTION, value, hash); mysql_variables.server_set_hash_and_value(session, SQL_COLLATION_CONNECTION, value, hash); mysql_variables.client_set_hash_and_value(session, SQL_CHARACTER_SET, value, hash); mysql_variables.server_set_hash_and_value(session, SQL_CHARACTER_SET, value, hash); return true; } return false; } inline bool verify_server_variable(MySQL_Session* session, int idx, uint32_t client_hash, uint32_t server_hash) { if (client_hash && client_hash != server_hash) { // Edge case for set charset command, because we do not know database character set // for now we are setting connection and collation to empty if (idx == SQL_CHARACTER_SET_CONNECTION || idx == SQL_COLLATION_CONNECTION ) { if (mysql_variables.client_get_hash(session, idx) == 0) { mysql_variables.server_set_hash_and_value(session, idx, "", 0); return false; } } // this variable is relevant only if status == SETTING_VARIABLE session->changing_variable_idx = (enum mysql_variable_name)idx; 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: // LCOV_EXCL_START proxy_error("Wrong status %d\n", session->status); assert(0); break; // LCOV_EXCL_STOP } session->set_status(mysql_tracked_variables[idx].status); mysql_variables.server_set_value(session, idx, mysql_variables.client_get_value(session, idx)); return true; } return false; } 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 * 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()); } } 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 * 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; }