diff --git a/include/MySQL_Thread.h b/include/MySQL_Thread.h index b3d1b8364..d41f58c72 100644 --- a/include/MySQL_Thread.h +++ b/include/MySQL_Thread.h @@ -192,7 +192,7 @@ class __attribute__((aligned(64))) MySQL_Thread : public Base_Thread pthread_mutex_t thread_mutex; // if set_parser_algorithm == 2 , a single thr_SetParser is used - SetParser *thr_SetParser; + SetParser *thr_SetParser; MySQL_Thread(); ~MySQL_Thread(); diff --git a/include/PgSQL_Thread.h b/include/PgSQL_Thread.h index 9f1f1b17d..32e5e4b4b 100644 --- a/include/PgSQL_Thread.h +++ b/include/PgSQL_Thread.h @@ -244,7 +244,7 @@ public: pthread_mutex_t thread_mutex; // if set_parser_algorithm == 2 , a single thr_SetParser is used - SetParser* thr_SetParser; + SetParser* thr_SetParser; /** * @brief Default constructor for the PgSQL_Thread class. diff --git a/include/set_parser.h b/include/set_parser.h index 73ff9e085..68d55bf21 100644 --- a/include/set_parser.h +++ b/include/set_parser.h @@ -9,6 +9,7 @@ //#define PARSERDEBUG +template class SetParser { private: // parse1v2 variables used for compile the RE only once diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index c529cfbdd..f458a4e33 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -5714,7 +5714,7 @@ void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C if (session_type == PROXYSQL_SESSION_MYSQL) { __sync_fetch_and_add(&MyHGM->status.frontend_use_db, 1); string nq=string((char *)pkt->ptr+sizeof(mysql_hdr)+1,pkt->size-sizeof(mysql_hdr)-1); - SetParser parser(nq); + SetParser parser(nq); string errmsg = ""; string schemaname = parser.parse_USE_query(errmsg); if (schemaname != "") { @@ -5992,7 +5992,7 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C ) { proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Parsing SET command %s\n", nq.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Parsing SET command = %s\n", nq.c_str()); - SetParser parser(nq); + SetParser parser(nq); std::map> set = {}; if (mysql_thread___set_parser_algorithm == 1) { // legacy behavior set = parser.parse1(); @@ -6545,7 +6545,7 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } } } else if (match_regexes && match_regexes[2]->match(dig)) { - SetParser parser(nq); + SetParser parser(nq); std::map> set = parser.parse2(); for(auto it = std::begin(set); it != std::end(set); ++it) { @@ -6610,7 +6610,7 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } } } else if (match_regexes && match_regexes[3]->match(dig)) { - SetParser parser(nq); + SetParser parser(nq); std::string charset = parser.parse_character_set(); const MARIADB_CHARSET_INFO * c; if (!charset.empty()) { diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index 5d8db5b1a..6a0adb3d8 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -2951,7 +2951,7 @@ bool MySQL_Thread::init() { mypolls.add(POLLIN, pipefd[0], NULL, 0); assert(i==0); - thr_SetParser = new SetParser(""); + thr_SetParser = new SetParser(""); match_regexes=(Session_Regex **)malloc(sizeof(Session_Regex *)*4); // match_regexes[0]=new Session_Regex((char *)"^SET (|SESSION |@@|@@session.)SQL_LOG_BIN( *)(:|)=( *)"); match_regexes[0] = NULL; // NOTE: historically we used match_regexes[0] for SET SQL_LOG_BIN . Not anymore diff --git a/lib/PgSQL_Session.cpp b/lib/PgSQL_Session.cpp index 030eb0e64..d37a30ac7 100644 --- a/lib/PgSQL_Session.cpp +++ b/lib/PgSQL_Session.cpp @@ -5013,7 +5013,7 @@ bool PgSQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C ) { proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Parsing SET command %s\n", nq.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Parsing SET command = %s\n", nq.c_str()); - SetParser parser(nq); + SetParser parser(nq); std::map> set = {}; if (pgsql_thread___set_parser_algorithm == 1) { // legacy behavior set = parser.parse1(); diff --git a/lib/PgSQL_Thread.cpp b/lib/PgSQL_Thread.cpp index db70ee021..a3919eaa6 100644 --- a/lib/PgSQL_Thread.cpp +++ b/lib/PgSQL_Thread.cpp @@ -2844,7 +2844,7 @@ bool PgSQL_Thread::init() { mypolls.add(POLLIN, pipefd[0], NULL, 0); assert(i == 0); - thr_SetParser = new SetParser(""); + thr_SetParser = new SetParser(""); match_regexes = (Session_Regex**)malloc(sizeof(Session_Regex*) * 4); // match_regexes[0]=new Session_Regex((char *)"^SET (|SESSION |@@|@@session.)SQL_LOG_BIN( *)(:|)=( *)"); match_regexes[0] = NULL; // NOTE: historically we used match_regexes[0] for SET SQL_LOG_BIN . Not anymore diff --git a/lib/set_parser.cpp b/lib/set_parser.cpp index 012f85fc4..d1fa14fd6 100644 --- a/lib/set_parser.cpp +++ b/lib/set_parser.cpp @@ -39,20 +39,23 @@ static void remove_quotes(string& v) { SetParser::SetParser(std::string nq, int verb) { verbosity = verb; #else -SetParser::SetParser(std::string nq) { +template +SetParser::SetParser(std::string nq) { #endif parse1v2_init = false; set_query(nq); } -SetParser::~SetParser() { +template +SetParser::~SetParser() { if (parse1v2_init == true) { delete parse1v2_opt2; delete parse1v2_re; } } -void SetParser::set_query(const std::string& nq) { +template +void SetParser::set_query(const std::string& nq) { int query_no_space_length = nq.length(); char *query_no_space=(char *)malloc(query_no_space_length+1); memcpy(query_no_space,nq.c_str(),query_no_space_length); @@ -80,7 +83,8 @@ void SetParser::set_query(const std::string& nq) { #define VAR_VALUE_P1_6 "|(?: )+" #define VAR_VALUE_P1 "(" VAR_VALUE_P1_1 VAR_VALUE_P1_2 VAR_VALUE_P1_3 VAR_VALUE_P1_4 VAR_VALUE_P1_5 VAR_VALUE_P1_6 ")" -std::map> SetParser::parse1() { +template +std::map> SetParser::parse1() { #ifdef DEBUG proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "Parsing query %s\n", query.c_str()); #endif // DEBUG @@ -148,7 +152,8 @@ VALGRIND_ENABLE_ERROR_REPORTING; return result; } -void SetParser::generateRE_parse1v2() { +template +void SetParser::generateRE_parse1v2() { vector quote_symbol = {"\"", "'", "`"}; vector var_patterns = {}; { @@ -306,7 +311,15 @@ void SetParser::generateRE_parse1v2() { } #endif - const std::string pattern="(?:" NAMES SPACES + name_value + "(?: +COLLATE +" + name_value + "|)" "|" + var_1 + SPACES "(?:|:)=" SPACES + var_value + ") *,? *"; + std::string pattern; + if constexpr (std::is_same_v) { + pattern = "(?:" NAMES SPACES + name_value + "(?: +COLLATE +" + name_value + "|)" "|" + var_1 + SPACES "(?:|:)=" SPACES + var_value + ") *,? *"; + } else if constexpr (std::is_same_v) { + pattern = "(?:" NAMES SPACES + name_value + "(?: +COLLATE +" + name_value + "|)" "|" + var_1 + SPACES "(?:|:)(?:TO|=)" SPACES + var_value + ") *,? *"; + } else { + assert(0); + } + #ifdef DEBUG VALGRIND_DISABLE_ERROR_REPORTING; #endif // DEBUG @@ -320,7 +333,8 @@ VALGRIND_DISABLE_ERROR_REPORTING; parse1v2_init = true; } -std::map> SetParser::parse1v2() { +template +std::map> SetParser::parse1v2() { std::map> result = {}; @@ -391,8 +405,8 @@ VALGRIND_ENABLE_ERROR_REPORTING; return result; } - -std::map> SetParser::parse2() { +template +std::map> SetParser::parse2() { #ifdef DEBUG proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "Parsing query %s\n", query.c_str()); @@ -438,7 +452,8 @@ std::map> SetParser::parse2() { return result; } -std::string SetParser::parse_character_set() { +template<> +std::string SetParser::parse_character_set() { #ifdef DEBUG proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "Parsing query %s\n", query.c_str()); #endif // DEBUG @@ -462,7 +477,32 @@ std::string SetParser::parse_character_set() { return value4; } -std::string SetParser::parse_USE_query(std::string& errmsg) { +template<> +std::string SetParser::parse_character_set() { +#ifdef DEBUG + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "Parsing query %s\n", query.c_str()); +#endif // DEBUG + re2::RE2::Options *opt2=new re2::RE2::Options(RE2::Quiet); + opt2->set_case_sensitive(false); + opt2->set_longest_match(false); + + re2::RE2 re0("^\\s*SET\\s+", *opt2); + re2::RE2::Replace(&query, re0, ""); + + std::map> result; + const std::string pattern = "(client_encoding|names)\\s*(|=|TO)\\s*['\"]?([A-Z_0-9]+)['\"]?"; + re2::RE2 re(pattern, *opt2); + std::string var; + std::string value1, value2, value3; + re2::StringPiece input(query); + re2::RE2::Consume(&input, re, &value1, &value2, &value3); + + delete opt2; + return value3; +} + +template +std::string SetParser::parse_USE_query(std::string& errmsg) { #ifdef DEBUG proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "Parsing query %s\n", query.c_str()); #endif // DEBUG @@ -513,8 +553,8 @@ std::string SetParser::parse_USE_query(std::string& errmsg) { return dbname; } - -std::string SetParser::remove_comments(const std::string& q) { +template +std::string SetParser::remove_comments(const std::string& q) { std::string result = ""; bool in_multiline_comment = false; @@ -558,7 +598,8 @@ std::string SetParser::remove_comments(const std::string& q) { #ifdef DEBUG -void SetParser::test_parse_USE_query() { +template +void SetParser::test_parse_USE_query() { // Define vector of pairs (query, expected dbname) std::vector> testCases = { @@ -621,3 +662,6 @@ void SetParser::test_parse_USE_query() { } } #endif // DEBUG + +template class SetParser; +template class SetParser; diff --git a/src/main.cpp b/src/main.cpp index f195bea15..a005db5e3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2325,7 +2325,7 @@ int main(int argc, const char * argv[]) { #ifdef DEBUG { // Automated testing - SetParser parser(""); + SetParser parser(""); parser.test_parse_USE_query(); } #endif // DEBUG