Adding SET TRANSACTION ISOLATION LEVEL * support

pull/4280/head
Rahim Kanji 3 years ago
parent fb53926cf5
commit a3d29863e8

@ -39,11 +39,13 @@ public:
bool client_set_value(MySQL_Session* session, int idx, const std::string& value);
bool client_set_hash_and_value(MySQL_Session* session, int idx, const std::string& value, uint32_t hash);
void client_reset_value(MySQL_Session* session, int idx);
const char* client_get_value(MySQL_Session* session, int idx) const;
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);
void server_reset_value(MySQL_Session* session, int idx);
const char* server_get_value(MySQL_Session* session, int idx) const;
inline uint32_t server_get_hash(MySQL_Session* session, int idx) const;

@ -332,3 +332,5 @@ std::string trim(const std::string& s);
* @return An 'unique_ptr' holding the resulting 'SQLite3_result'.
*/
std::unique_ptr<SQLite3_result> get_SQLite3_resulset(MYSQL_RES* resultset);
std::vector<std::string> split_string(const std::string& str, char delimiter);

@ -221,6 +221,8 @@ enum mysql_variable_name {
SQL_TIME_ZONE,
SQL_TIMESTAMP,
SQL_TMP_TABLE_SIZE,
SQL_NEXT_ISOLATION_LEVEL,
SQL_NEXT_TRANSACTION_READ,
SQL_UNIQUE_CHECKS,
SQL_WSREP_OSU_METHOD,
SQL_NAME_LAST_HIGH_WM,
@ -254,6 +256,8 @@ enum session_status {
SETTING_MULTIPLE_VARIABLES,
SETTING_SET_NAMES,
SHOW_WARNINGS,
SETTING_NEXT_ISOLATION_LEVEL,
SETTING_NEXT_TRANSACTION_READ,
session_status___NONE // special marker
};
@ -1188,6 +1192,8 @@ mysql_variable_st mysql_tracked_variables[] {
{ SQL_TIME_ZONE, SETTING_VARIABLE, true, false, false, false, (char *)"time_zone", NULL, (char *)"SYSTEM" , false} ,
{ SQL_TIMESTAMP, SETTING_VARIABLE, false, false, true, false, (char *)"timestamp", NULL, (char *)"" , false} ,
{ SQL_TMP_TABLE_SIZE, SETTING_VARIABLE, false, false, true, false, (char *)"tmp_table_size", NULL, (char *)"" , false} ,
{ SQL_NEXT_ISOLATION_LEVEL, SETTING_NEXT_ISOLATION_LEVEL, false, true, false, false, (char *)"transaction isolation level", (char *)"next_isolation_level", (char *)"READ COMMITTED" , false} ,
{ SQL_NEXT_TRANSACTION_READ, SETTING_NEXT_TRANSACTION_READ, false, true, false, false, (char *)"transaction read", (char *)"next_transaction_read", (char *)"WRITE" , false} ,
{ SQL_UNIQUE_CHECKS, SETTING_VARIABLE, true, false, false, true, (char *)"unique_checks", NULL, (char *)"" , false} ,
{ SQL_WSREP_OSU_METHOD, SETTING_VARIABLE, true, false, false, false, (char *)"wsrep_osu_method", NULL, (char *)"" , false} ,

@ -2582,6 +2582,15 @@ bool MySQL_Session::handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, co
myds->DSS = STATE_MARIADB_GENERIC;
st=previous_status.top();
previous_status.pop();
if (strncasecmp("transaction isolation level", var_name, sizeof("transaction isolation level")-1) == 0) {
mysql_variables.server_reset_value(this, SQL_NEXT_ISOLATION_LEVEL);
mysql_variables.client_reset_value(this, SQL_NEXT_ISOLATION_LEVEL);
} else if (strncasecmp("transaction read", var_name, sizeof("transaction read")-1) == 0) {
mysql_variables.server_reset_value(this, SQL_NEXT_TRANSACTION_READ);
mysql_variables.client_reset_value(this, SQL_NEXT_TRANSACTION_READ);
}
NEXT_IMMEDIATE_NEW(st);
} else {
if (rc==-1) {
@ -5143,6 +5152,8 @@ handler_again:
case SETTING_TRANSACTION_READ:
case SETTING_CHARSET:
case SETTING_VARIABLE:
case SETTING_NEXT_ISOLATION_LEVEL:
case SETTING_NEXT_TRANSACTION_READ:
{
int rc = 0;
if (mysql_variables.update_variable(this, status, rc)) {
@ -6550,27 +6561,51 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C
} else if (match_regexes && match_regexes[2]->match(dig)) {
SetParser parser(nq);
std::map<std::string, std::vector<std::string>> set = parser.parse2();
for(auto it = std::begin(set); it != std::end(set); ++it) {
std::string var = it->first;
auto values = std::begin(it->second);
proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET variable %s\n", var.c_str());
if (var == "isolation level") {
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 (mysql_variables.client_get_hash(this, SQL_ISOLATION_LEVEL) != isolation_level_int) {
if (!mysql_variables.client_set_value(this, SQL_ISOLATION_LEVEL, value1.c_str()))
return false;
proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection TRANSACTION ISOLATION LEVEL to %s\n", value1.c_str());
const std::vector<std::string>& val = split_string(it->first, ':');
if (val.size() == 2) {
const auto values = std::begin(it->second);
const std::string& var = val[1];
enum mysql_variable_name isolation_level_val;
enum mysql_variable_name transaction_read_val;
if (val[0] == "SESSION") {
isolation_level_val = SQL_ISOLATION_LEVEL;
transaction_read_val = SQL_TRANSACTION_READ;
} else {
isolation_level_val = SQL_NEXT_ISOLATION_LEVEL;
transaction_read_val = SQL_NEXT_TRANSACTION_READ;
}
} 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 (mysql_variables.client_get_hash(this, SQL_TRANSACTION_READ) != transaction_read_int) {
if (!mysql_variables.client_set_value(this, SQL_TRANSACTION_READ, value1.c_str()))
return false;
proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection TRANSACTION READ to %s\n", value1.c_str());
proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET variable %s\n", var.c_str());
if (var == "isolation level") {
const std::string& value1 = *values;
proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET %s TRANSACTION ISOLATION LEVEL value %s\n", val[0].c_str(), value1.c_str());
const uint32_t isolation_level_int = SpookyHash::Hash32(value1.c_str(), value1.length(), 10);
if (mysql_variables.client_get_hash(this, isolation_level_val) != isolation_level_int) {
if (!mysql_variables.client_set_value(this, isolation_level_val, value1.c_str()))
return false;
proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection TRANSACTION ISOLATION LEVEL to %s\n", value1.c_str());
}
} else if (var == "read") {
const std::string& value1 = *values;
proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET %s TRANSACTION READ value %s\n", val[0].c_str(), value1.c_str());
const uint32_t transaction_read_int = SpookyHash::Hash32(value1.c_str(), value1.length(), 10);
if (mysql_variables.client_get_hash(this, transaction_read_val) != transaction_read_int) {
if (!mysql_variables.client_set_value(this, transaction_read_val, value1.c_str()))
return false;
proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection TRANSACTION READ to %s\n", value1.c_str());
}
} else {
unable_to_parse_set_statement(lock_hostgroup);
return false;
}
} else {
unable_to_parse_set_statement(lock_hostgroup);

@ -94,6 +94,24 @@ bool MySQL_Variables::client_set_hash_and_value(MySQL_Session* session, int idx,
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");
@ -222,6 +240,25 @@ void MySQL_Variables::server_set_value(MySQL_Session* session, int idx, const ch
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);

@ -1,6 +1,6 @@
#include <vector>
#include <memory>
#include <sstream>
#include "gen_utils.h"
@ -264,4 +264,16 @@ std::unique_ptr<SQLite3_result> get_SQLite3_resulset(MYSQL_RES* resultset) {
mysql_data_seek(resultset, 0);
return sqlite_result;
}
std::vector<std::string> split_string(const std::string& str, char delimiter) {
std::vector<std::string> tokens {};
std::string token {};
std::istringstream tokenStream(str);
while (std::getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}

@ -415,7 +415,9 @@ std::map<std::string,std::vector<std::string>> SetParser::parse2() {
proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "SET parsing: v1='%s' , v2='%s' , v3='%s' , v4='%s' , v5='%s'\n", value1.c_str(), value2.c_str(), value3.c_str(), value4.c_str(), value5.c_str());
#endif // DEBUG
std::string key;
if (value1 != "") { // session is specified
bool is_session = (value1 != "");
//if (value1 != "") { // session is specified
if (value2 != "") { // isolation level
key = value2;
std::transform(value3.begin(), value3.end(), value3.begin(), ::toupper);
@ -425,9 +427,9 @@ std::map<std::string,std::vector<std::string>> SetParser::parse2() {
std::transform(value5.begin(), value5.end(), value5.begin(), ::toupper);
op.push_back(value5);
}
}
//}
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
result[key] = op;
result[std::string((is_session == true) ? "SESSION:" : ":") + key] = op;
}
delete opt2;

Loading…
Cancel
Save