From 246a9d828a4b4c7bea2fa7fcbe409f81f733b161 Mon Sep 17 00:00:00 2001 From: val Date: Thu, 9 Apr 2020 12:12:36 +0000 Subject: [PATCH] use separate function for set names verification --- include/MySQL_Variables.h | 2 + lib/MySQL_Session.cpp | 5 ++ lib/MySQL_Variables.cpp | 132 +++++++++++++++++++++++--------------- 3 files changed, 87 insertions(+), 52 deletions(-) diff --git a/include/MySQL_Variables.h b/include/MySQL_Variables.h index 76c8b93b9..64a27a92b 100644 --- a/include/MySQL_Variables.h +++ b/include/MySQL_Variables.h @@ -21,6 +21,7 @@ typedef bool (*update_var)(MySQL_Session* session, int idx, int &_rc); bool validate_charset(MySQL_Session* session, int idx, int &_rc); bool update_server_variable(MySQL_Session* session, int idx, int &_rc); bool verify_server_variable(MySQL_Session* session, int idx, uint32_t client_hash, uint32_t server_hash); +bool verify_set_names(MySQL_Session* session); bool logbin_update_server_variable(MySQL_Session* session, int idx, int &_rc); class MySQL_Variables { @@ -38,6 +39,7 @@ public: uint32_t client_get_hash(MySQL_Session* session, int idx) const; void server_set_value(MySQL_Session* session, int idx, const char* value); + void server_set_hash_and_value(MySQL_Session* session, int idx, const char* value, uint32_t hash); const char* server_get_value(MySQL_Session* session, int idx) const; inline uint32_t server_get_hash(MySQL_Session* session, int idx) const; diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 8dd06bc95..5010836ce 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -3553,6 +3553,11 @@ handler_again: goto handler_again; } + // Optimize network traffic when we can use 'SET NAMES' + if (verify_set_names(this)) { + goto handler_again; + } + for (auto i = 0; i < SQL_NAME_LAST; i++) { if(!myconn->var_absent[i] && mysql_variables.verify_variable(this, i)) { goto handler_again; diff --git a/lib/MySQL_Variables.cpp b/lib/MySQL_Variables.cpp index 2c3ca0de9..90779de03 100644 --- a/lib/MySQL_Variables.cpp +++ b/lib/MySQL_Variables.cpp @@ -74,6 +74,20 @@ bool MySQL_Variables::client_set_hash_and_value(MySQL_Session* session, int idx, return true; } +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); +} + + 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"); @@ -336,61 +350,75 @@ bool update_server_variable(MySQL_Session* session, int idx, int &_rc) { return ret; } +bool verify_set_names(MySQL_Session* session) { + uint32_t client_charset_hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET_CLIENT); + 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: + proxy_error("Wrong status %d\n", session->status); + assert(0); + break; + } + 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 != server_hash) { - uint32_t client_charset_hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET_CLIENT); - uint32_t results_charset_hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET_RESULTS); - uint32_t connection_charset_hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET_CONNECTION); - uint32_t collation_hash = mysql_variables.client_get_hash(session, SQL_COLLATION_CONNECTION); - - bool process_charset_variable = ((idx == SQL_CHARACTER_SET_CLIENT) || (idx == SQL_CHARACTER_SET_RESULTS) || (idx == SQL_CHARACTER_SET_CONNECTION) || (idx == SQL_COLLATION_CONNECTION)); - bool is_set_names_hash = ((client_charset_hash == results_charset_hash) && (client_charset_hash == connection_charset_hash) && (client_charset_hash == collation_hash)); - - if (process_charset_variable && is_set_names_hash) { - 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: - proxy_error("Wrong status %d\n", session->status); - assert(0); - break; - } - session->set_status(SETTING_SET_NAMES); - mysql_variables.server_set_value(session, SQL_CHARACTER_SET_CLIENT, mysql_variables.client_get_value(session, SQL_CHARACTER_SET_CLIENT)); - mysql_variables.server_set_value(session, SQL_CHARACTER_SET_RESULTS, mysql_variables.client_get_value(session, SQL_CHARACTER_SET_RESULTS)); - mysql_variables.server_set_value(session, SQL_CHARACTER_SET_CONNECTION, mysql_variables.client_get_value(session, SQL_CHARACTER_SET_CONNECTION)); - mysql_variables.server_set_value(session, SQL_COLLATION_CONNECTION, mysql_variables.client_get_value(session, SQL_COLLATION_CONNECTION)); - mysql_variables.client_set_value(session, SQL_CHARACTER_SET, mysql_variables.client_get_value(session, SQL_CHARACTER_SET_CLIENT)); - mysql_variables.server_set_value(session, SQL_CHARACTER_SET, mysql_variables.client_get_value(session, SQL_CHARACTER_SET_CLIENT)); - return true; - } else { - 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: - proxy_error("Wrong status %d\n", session->status); - assert(0); - break; - } - session->set_status(mysql_tracked_variables[idx].status); - mysql_variables.server_set_value(session, idx, mysql_variables.client_get_value(session, idx)); - return true; + 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: + proxy_error("Wrong status %d\n", session->status); + assert(0); + break; } - + 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; }