From a908f2a17b2d93ee5ef0c0bfc9740bdd3f724f9e Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Fri, 7 Jul 2023 12:18:52 +0500 Subject: [PATCH] Added transaction_isolation_level and transaction_read_only variable support. --- lib/MySQL_Session.cpp | 43 ++++++++++++++++++++++++++++++++++++++----- lib/MySQL_Thread.cpp | 2 +- lib/set_parser.cpp | 20 ++++++++++++++------ 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 10e0b9e4c..b722494c0 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -2546,10 +2546,16 @@ bool MySQL_Session::handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, co char *sv = mybe->server_myds->myconn->mysql->server_version; if (strncmp(sv,(char *)"8",1)==0) { sprintf(query,q,"transaction_isolation", var_value); - } - else { + } else { sprintf(query,q,"tx_isolation", var_value); } + } else if (strncasecmp("tx_read_only", var_name, 12) == 0) { + char* sv = mybe->server_myds->myconn->mysql->server_version; + if (strncmp(sv, (char *)"8", 1) == 0) { + sprintf(query,q,"transaction_read_only", var_value); + } else { + sprintf(query,q,"tx_read_only", var_value); + } } else if (strncasecmp("aurora_read_replica_read_committed", var_name, 34) == 0) { // If aurora_read_replica_read_committed is set, isolation level is // internally reset so that it will be set again. @@ -2583,10 +2589,10 @@ bool MySQL_Session::handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, co st=previous_status.top(); previous_status.pop(); - if (strncasecmp("transaction isolation level", var_name, sizeof("transaction isolation level")-1) == 0) { + if (strcasecmp("transaction isolation level", var_name) == 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) { + } else if (strcasecmp("transaction read", var_name) == 0) { mysql_variables.server_reset_value(this, SQL_NEXT_TRANSACTION_READ); mysql_variables.client_reset_value(this, SQL_NEXT_TRANSACTION_READ); } @@ -6443,6 +6449,33 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C return false; proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection TX ISOLATION to %s\n", value1.c_str()); } + } else if (var == "tx_read_only") { + std::string value1 = *values; + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET tx_read_only value %s\n", value1.c_str()); + + if ( + (value1 == "0") || + (strcasecmp(value1.c_str(), "false")==0) || + (strcasecmp(value1.c_str(), "off")==0) + ) { + value1 = "WRITE"; + } else if ( + (value1 == "1") || + (strcasecmp(value1.c_str(), "true")==0) || + (strcasecmp(value1.c_str(), "on")==0) + ) { + value1 = "ONLY"; + } else { + //proxy_warning("Unknown tx_read_only value \"%s\"\n", value1.c_str()); + unable_to_parse_set_statement(lock_hostgroup); + return false; + } + uint32_t read_only_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); + if (mysql_variables.client_get_hash(this, SQL_TRANSACTION_READ) != read_only_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 TX ACCESS MODE to READ %s\n", value1.c_str()); + } } else if (std::find(mysql_variables.ignore_vars.begin(), mysql_variables.ignore_vars.end(), var) != mysql_variables.ignore_vars.end()) { // this is a variable we parse but ignore // see MySQL_Variables::MySQL_Variables() for a list of ignored variables @@ -6574,7 +6607,7 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C enum mysql_variable_name isolation_level_val; enum mysql_variable_name transaction_read_val; - if (val[0] == "SESSION") { + if (val[0] == "session") { isolation_level_val = SQL_ISOLATION_LEVEL; transaction_read_val = SQL_TRANSACTION_READ; } else { diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index f8a20c843..f1a17a215 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -2975,7 +2975,7 @@ bool MySQL_Thread::init() { match_regexes[0] = NULL; // NOTE: historically we used match_regexes[0] for SET SQL_LOG_BIN . Not anymore std::stringstream ss; - ss << "^SET (|SESSION |@@|@@session.|@@local.)`?(" << mysql_variables.variables_regexp << "SESSION_TRACK_GTIDS|TX_ISOLATION)`?( *)(:|)=( *)"; + ss << "^SET (|SESSION |@@|@@session.|@@local.)`?(" << mysql_variables.variables_regexp << "SESSION_TRACK_GTIDS|TX_ISOLATION|TX_READ_ONLY|TRANSACTION_ISOLATION|TRANSACTION_READ_ONLY)`?( *)(:|)=( *)"; match_regexes[1]=new Session_Regex((char *)ss.str().c_str()); match_regexes[2]=new Session_Regex((char *)"^SET(?: +)(|SESSION +)TRANSACTION(?: +)(?:(?:(ISOLATION(?: +)LEVEL)(?: +)(REPEATABLE(?: +)READ|READ(?: +)COMMITTED|READ(?: +)UNCOMMITTED|SERIALIZABLE))|(?:(READ)(?: +)(WRITE|ONLY)))"); diff --git a/lib/set_parser.cpp b/lib/set_parser.cpp index 737083749..807daef21 100644 --- a/lib/set_parser.cpp +++ b/lib/set_parser.cpp @@ -104,7 +104,12 @@ VALGRIND_ENABLE_ERROR_REPORTING; } } else if (value4 != "") { // VARIABLE - value5.erase(value5.find_last_not_of(" \n\r\t,")+1); + if (strcasecmp("transaction_isolation", value4.c_str()) == 0) { + value4 = "tx_isolation"; + } else if (strcasecmp("transaction_read_only", value4.c_str()) == 0) { + value4 = "tx_read_only"; + } + value5.erase(value5.find_last_not_of(" \n\r\t,")+1); key = value4; if (value5 == "''" || value5 == "\"\"") { op.push_back(""); @@ -356,6 +361,11 @@ VALGRIND_ENABLE_ERROR_REPORTING; } } else if (value4 != "") { // VARIABLE + if (strcasecmp("transaction_isolation", value4.c_str()) == 0) { + value4 = "tx_isolation"; + } else if (strcasecmp("transaction_read_only", value4.c_str()) == 0) { + value4 = "tx_read_only"; + } value5.erase(value5.find_last_not_of(" \n\r\t,")+1); key = value4; if (value5 == "''" || value5 == "\"\"") { @@ -415,21 +425,19 @@ std::map> 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; - - bool is_session = (value1 != ""); //if (value1 != "") { // session is specified if (value2 != "") { // isolation level - key = value2; + key = value1 + ":" + value2; std::transform(value3.begin(), value3.end(), value3.begin(), ::toupper); op.push_back(value3); } else { - key = value4; + key = value1 + ":" + value4; std::transform(value5.begin(), value5.end(), value5.begin(), ::toupper); op.push_back(value5); } //} std::transform(key.begin(), key.end(), key.begin(), ::tolower); - result[std::string((is_session == true) ? "SESSION:" : ":") + key] = op; + result[key] = op; } delete opt2;