Merge pull request #3381 from sysown/v2.1.1-3184-r

Parse "SET wait_timeout" #3184
pull/3392/head
René Cannaò 5 years ago committed by GitHub
commit 24da762c38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -30,7 +30,8 @@ class MySQL_Variables {
public:
std::string variables_regexp;
// ignore_vars is a list of all variables that proxysql will parse but ignore its value
std::vector<std::string> ignore_vars;
public:
MySQL_Variables();

@ -5386,6 +5386,7 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C
unsigned int nTrx=NumActiveTransactions();
if ((locked_on_hostgroup == -1) && (strncasecmp(dig,(char *)"SET ",4)==0)) {
// this code is executed only if locked_on_hostgroup is not set yet
// if locked_on_hostgroup is set, we do not try to parse the SET statement
#ifdef DEBUG
{
string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength);
@ -5738,11 +5739,20 @@ 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 {
} 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
#ifdef DEBUG
std::string value1 = *values;
std::size_t found_at = value1.find("@");
if (found_at != std::string::npos) {
unable_to_parse_set_statement(lock_hostgroup);
proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET %s value %s\n", var.c_str(), value1.c_str());
#endif // DEBUG
} else {
// if we reach here, proxysql didn't recognize every variable in a set statement
// unable_to_parse_set_statement() will consider the value of qpo->multiplex,
// therefore unable_to_parse_set_statement() may set or not set lock_hostgroup.
// if lock_hostgroup is set, we return immediately
unable_to_parse_set_statement(lock_hostgroup);
if (lock_hostgroup) {
return false;
}
}

@ -20,6 +20,10 @@ update_var MySQL_Variables::updaters[SQL_NAME_LAST];
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");
variables_regexp = "";
for (auto i = 0; i < SQL_NAME_LAST; i++) {
if (i == SQL_CHARACTER_SET || i == SQL_CHARACTER_ACTION || i == SQL_SET_NAMES) {
@ -38,6 +42,10 @@ MySQL_Variables::MySQL_Variables() {
variables_regexp += "|";
}
}
for (std::vector<std::string>::iterator it=ignore_vars.begin(); it != ignore_vars.end(); it++) {
variables_regexp += *it;
variables_regexp += "|";
}
}
MySQL_Variables::~MySQL_Variables() {}

@ -34,7 +34,7 @@ std::map<std::string,std::vector<std::string>> SetParser::parse1() {
std::map<std::string,std::vector<std::string>> result;
#define SESSION_P1 "(?:|SESSION +|@@|@@session.)"
#define VAR_P1 "(\\w+)"
#define VAR_P1 "(@\\w+|\\w+)"
//#define VAR_VALUE "((?:[\\w/\\d:\\+\\-]|,)+)"
//#define VAR_VALUE "((?:CONCAT\\((?:(REPLACE|CONCAT)\\()+@@sql_mode,(?:(?:'|\\w|,| |\"|\\))+(?:\\)))|(?:[@\\w/\\d:\\+\\-]|,)+|(?:)))"
#define VAR_VALUE_P1 "(((?:CONCAT\\()*(?:((?: )*REPLACE|IFNULL|CONCAT)\\()+(?: )*(?:NULL|@OLD_SQL_MODE|@@sql_mode),(?:(?:'|\\w|,| |\"|\\))+(?:\\))*)|(?:[@\\w/\\d:\\+\\-]|,)+|(?:)))"

@ -0,0 +1,112 @@
/**
* @file reg_test_3184-set_wait_timeout-t.cpp
* @brief This test is a regression test for issue #3184.
* @details The test performs all the valid supported combinations of
* 'SET @@wait_timeout' queries that ProxySQL should ignore, returning
* an okay packet. The check is performed via 'PROXYSQL INTERNAL SESSION',
* checking that multiplexing hasn't been disable due to an unknown
* 'SET' statement.
*
* @date 2021-03-26
*/
#include <vector>
#include <string>
#include <stdio.h>
#include <mysql.h>
#include "tap.h"
#include "command_line.h"
#include "utils.h"
#include "json.hpp"
using std::string;
using namespace nlohmann;
/**
* @brief Helper function to convert a 'MYSQL_RES' into a
* nlohmann::json.
*
* @param result The 'MYSQL_RES*' to be converted into JSON.
* @param j 'nlohmann::json' output parameter holding the
* converted 'MYSQL_RES' supplied.
*/
void parse_result_json_column(MYSQL_RES *result, json& j) {
if(!result) return;
MYSQL_ROW row;
while ((row = mysql_fetch_row(result))) {
j = json::parse(row[0]);
}
}
/**
* @brief Valid variations of 'SET wait_timeout' supported
* by ProxySQL to be ignored.
*/
std::vector<std::string> valids_set_wait_timeout {
"SET @@wait_timeout = 2147483",
"SET @@wait_timeout=2147483",
"SET @@SESSION.wait_timeout = 2147483",
"SET @@SESSION.wait_timeout=2147483",
"SET wait_timeout = 2147483",
"SET wait_timeout=2147483",
"SET SESSION wait_timeout = 2147483",
"SET SESSION wait_timeout=2147483",
"SET @@net_read_timeout = 2147483",
"SET @@net_read_timeout=2147483",
"SET @@SESSION.net_read_timeout = 2147483",
"SET @@SESSION.net_read_timeout=2147483",
"SET net_read_timeout = 2147483",
"SET net_read_timeout=2147483",
"SET SESSION net_read_timeout = 2147483",
"SET SESSION net_read_timeout=2147483",
"SET @@interactive_timeout = 2147483",
"SET @@interactive_timeout=2147483",
"SET @@SESSION.interactive_timeout = 2147483",
"SET @@SESSION.interactive_timeout=2147483",
"SET interactive_timeout = 2147483",
"SET interactive_timeout=2147483",
"SET SESSION interactive_timeout = 2147483",
"SET SESSION interactive_timeout=2147483"
};
int main(int argc, char** argv) {
CommandLine cl;
if (cl.getEnv()) {
diag("Failed to get the required environmental variables.");
return -1;
}
plan(2 * valids_set_wait_timeout.size());
MYSQL* proxysql_mysql = mysql_init(NULL);
if (!mysql_real_connect(proxysql_mysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_mysql));
return -1;
}
for (const auto& set_wait_timeout : valids_set_wait_timeout) {
int query_err = mysql_query(proxysql_mysql, set_wait_timeout.c_str());
ok (query_err == 0, "Query '%s' should be properly executed.", set_wait_timeout.c_str());
MYSQL_QUERY(proxysql_mysql, "PROXYSQL INTERNAL SESSION");
json j_status {};
MYSQL_RES* int_session_res = mysql_store_result(proxysql_mysql);
parse_result_json_column(int_session_res, j_status);
mysql_free_result(int_session_res);
bool found_backends = j_status.contains("backends");
ok(found_backends == false, "No backends should be found for the current connection.");
}
mysql_close(proxysql_mysql);
return exit_status();
}

@ -0,0 +1,141 @@
/**
* @file test_filtered_set_statements-t.cpp
* @brief Test for checking that all the supported 'SET statements' are
* handled properly by ProxySQL.
* @details The test performs all the valid supported combinations of
* all the specified 'SET' statements that should be specially handled
* by ProxySQL. For confirming that this is being the case, the test
* checks that 'sum_time' is always '0' for all these special queries
* after issuing them.
*
* @date 2021-03-26
*/
#include <vector>
#include <string>
#include <stdio.h>
#include <mysql.h>
#include "proxysql_utils.h"
#include "tap.h"
#include "command_line.h"
#include "utils.h"
#include <iostream>
/**
* @brief Queries to be tested that are known to be filtered by ProxySQL.
*
* TODO: Fill with all the statements that should be properly handled by ProxySQL.
*/
std::vector<std::pair<std::string, std::string>> filtered_set_queries {
{ "sql_mode", "" },
{ "wait_timeout", "param" },
{ "character_set_results", "latin1" },
{ "character_set_connection", "latin1" },
{ "character_set_database", "latin1" },
// TODO: This queries fails for some values
// { "character_set_server", "latin1" },
// { "character_set_client", "latin1" },
{ "autocommit", "1" },
{ "sql_select_limit", "4294967295" },
{ "net_write_timeout", "25" },
{ "max_join_size", "18446744073709551615" },
{ "wsrep_sync_wait", "12" },
{ "group_concat_max_len", "4294967295" },
{ "sql_safe_updates", "true" },
{ "session_track_gtids", "OWN_GTID" },
{ "interactive_timeout", "param" },
{ "net_read_timeout", "param" },
};
std::vector<std::string> get_valid_set_query_set(const std::string& set_query, const std::string param) {
std::vector<std::string> result {};
result.push_back(std::string("SET @@") + set_query + "=" + param);
result.push_back(std::string("SET @@") + set_query + " = " + param);
result.push_back(std::string("SET @@SESSION ") + set_query + " = " + param);
result.push_back(std::string("SET @@SESSION ") + set_query + "=" + param);
result.push_back(std::string("SET ") + set_query + "=" + param);
result.push_back(std::string("SET ") + set_query + " = " + param);
result.push_back(std::string("SET SESSION ") + set_query + "=" + param);
result.push_back(std::string("SET SESSION ") + set_query + " = " + param);
return result;
}
int main(int argc, char** argv) {
CommandLine cl;
if (cl.getEnv()) {
diag("Failed to get the required environmental variables.");
return -1;
}
// plan one test per statement attempt + one check 'SUM(sum_time) == 0' for each 'filtered_set_queries'
plan(filtered_set_queries.size() + filtered_set_queries.size()*get_valid_set_query_set("", "").size());
// create a regular connection to 'proxysql'
MYSQL* proxysql_mysql = mysql_init(NULL);
if (!mysql_real_connect(proxysql_mysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_mysql));
return -1;
}
// create a connection to 'proxysql_admin'
MYSQL* proxysql_admin = mysql_init(NULL);
if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_password, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
return -1;
}
// first clean the 'stats_mysql_query_digest' table
MYSQL_QUERY(proxysql_admin, "SELECT null FROM stats.stats_mysql_query_digest_reset LIMIT 0");
MYSQL_RES* reset_result = mysql_store_result(proxysql_admin);
mysql_free_result(reset_result);
std::string t_sum_query { "SELECT SUM(sum_time) FROM stats.stats_mysql_query_digest WHERE digest_text LIKE '%%%s%%'" };
for (const auto& filtered_query : filtered_set_queries) {
const std::vector<std::string> f_filtered_query_set =
get_valid_set_query_set(filtered_query.first, filtered_query.second);
for (const auto& set_query : f_filtered_query_set) {
int query_err = mysql_query(proxysql_mysql, set_query.c_str());
ok (query_err == 0, "Query '%s' should be properly executed.", set_query.c_str());
}
std::string sum_query { "" };
string_format(t_sum_query, sum_query, filtered_query.first.c_str());
MYSQL_QUERY(proxysql_admin, sum_query.c_str());
MYSQL_RES* sum_query_res = mysql_store_result(proxysql_admin);
int sum_sum_time = -1;
int field_count = mysql_num_fields(sum_query_res);
if (field_count == 1) {
MYSQL_ROW row = mysql_fetch_row(sum_query_res);
if (row[0] != nullptr) {
sum_sum_time = atoi(row[0]);
}
}
mysql_free_result(sum_query_res);
ok (
sum_sum_time == 0,
"The SUM(sum_time) of all the variations for the 'set_statements:%s' should be zero. Value was: %d",
filtered_query.first.c_str(),
sum_sum_time
);
}
// close proxysql connection
mysql_close(proxysql_mysql);
// close admin connection
mysql_close(proxysql_admin);
return exit_status();
}
Loading…
Cancel
Save