From 045d6bcaeb3abf2b32fde2ce4784932963175594 Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Thu, 16 Nov 2023 13:01:05 +0500 Subject: [PATCH] * Execute all test cases with 'CLIENT_DEPRECATE_EOF' both enabled and disabled. * Introduced 'ps_type' enum to differentiate between preparing a statement and executing a statement * Fixed issue where the warning count fails to reset when the SET statement generates a warning. * Resolved the issue where the 'server_status' and 'warning count' were not accurately represented in the statement. * Replaced 'mysql_warning_count' with 'mysql_stmt_warning_count' for retrieving the warning count in statements. * Added 'handle_warning' field in hostgroup_attributes TAP test * Updated warnings TAP test --- .../client_deprecate_eof.patch | 4 +- include/MySQL_Session.h | 8 +- lib/MySQL_Session.cpp | 15 +- lib/mysql_connection.cpp | 20 +- test/tap/tests/test_cluster_sync-t.cpp | 2 +- test/tap/tests/test_warnings-t.cpp | 459 ++++++++++++------ 6 files changed, 342 insertions(+), 166 deletions(-) diff --git a/deps/mariadb-client-library/client_deprecate_eof.patch b/deps/mariadb-client-library/client_deprecate_eof.patch index f7f11b3b61..2c7a611f50 100644 --- a/deps/mariadb-client-library/client_deprecate_eof.patch +++ b/deps/mariadb-client-library/client_deprecate_eof.patch @@ -653,7 +653,7 @@ index 0aaaf1a..229023b 100644 { /* allocate space for rows */ if (!(current= (MYSQL_ROWS *)ma_alloc_root(&result->alloc, sizeof(MYSQL_ROWS) + packet_len))) -@@ -276,10 +284,14 @@ int mthd_stmt_read_all_rows(MYSQL_STMT *stmt) +@@ -276,10 +284,16 @@ int mthd_stmt_read_all_rows(MYSQL_STMT *stmt) { *pprevious= 0; /* sace status info */ @@ -664,6 +664,8 @@ index 0aaaf1a..229023b 100644 + + if (stmt->mysql->server_capabilities & CLIENT_DEPRECATE_EOF && !is_data_packet) { + ma_read_ok_packet(stmt->mysql, p + 1, packet_len); ++ stmt->upsert_status.warning_count= stmt->mysql->warning_count; ++ stmt->upsert_status.server_status= stmt->mysql->server_status; + } else { + stmt->upsert_status.warning_count= stmt->mysql->warning_count= uint2korr(p + 1); + stmt->upsert_status.server_status= stmt->mysql->server_status= uint2korr(p + 3); diff --git a/include/MySQL_Session.h b/include/MySQL_Session.h index 049659306a..d2de482c79 100644 --- a/include/MySQL_Session.h +++ b/include/MySQL_Session.h @@ -24,6 +24,12 @@ enum proxysql_session_type { PROXYSQL_SESSION_NONE }; +enum ps_type : uint8_t { + ps_type_not_set = 0x0, + ps_type_prepare_stmt = 0x1, + ps_type_execute_stmt = 0x2 +}; + std::string proxysql_session_type_str(enum proxysql_session_type session_type); // these structs will be used for various regex hardcoded @@ -121,7 +127,7 @@ class MySQL_Session void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_SET_OPTION(PtrSize_t *); void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_STATISTICS(PtrSize_t *); void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_PROCESS_KILL(PtrSize_t *); - bool handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo(PtrSize_t *, bool *lock_hostgroup, bool ps=false); + bool handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo(PtrSize_t *, bool *lock_hostgroup, ps_type prepare_stmt_type=ps_type_not_set); void handler___client_DSS_QUERY_SENT___server_DSS_NOT_INITIALIZED__get_connection(); diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 24f6939d24..d904d84712 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -3289,7 +3289,7 @@ void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } assert(qpo); // GloQPro->process_mysql_query() should always return a qpo // setting 'prepared' to prevent fetching results from the cache if the digest matches - rc_break=handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo(&pkt, &lock_hostgroup, true); + rc_break=handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo(&pkt, &lock_hostgroup, ps_type_prepare_stmt); if (rc_break==true) { return; } @@ -3457,7 +3457,7 @@ void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C CurrentQuery.stmt_meta=stmt_meta; //current_hostgroup=qpo->destination_hostgroup; - rc_break=handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo(&pkt, &lock_hostgroup, true); + rc_break=handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo(&pkt, &lock_hostgroup, ps_type_execute_stmt); if (rc_break==true) { return; } @@ -5992,7 +5992,7 @@ int MySQL_Session::handler_WCD_SS_MCQ_qpo_Parse_SQL_LOG_BIN(PtrSize_t *pkt, bool } */ -bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo(PtrSize_t *pkt, bool *lock_hostgroup, bool prepared) { +bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo(PtrSize_t *pkt, bool *lock_hostgroup, ps_type prepare_stmt_type) { /* lock_hostgroup: If this variable is set to true, this session will get lock to a @@ -6027,7 +6027,7 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C return true; } - if (prepared) { // for prepared statement we exit here + if (prepare_stmt_type & ps_type_execute_stmt) { // for prepared statement execute we exit here reset_warning_hostgroup_flag_and_release_connection(); goto __exit_set_destination_hostgroup; } @@ -6043,7 +6043,6 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C if (warning_in_hg > -1) { proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing current_hostgroup to '%d'\n", warning_in_hg); current_hostgroup = warning_in_hg; - //warning_in_hg = -1; return false; } else { proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "No warnings were detected in the previous query. Sending an empty response.\n"); @@ -6951,12 +6950,12 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } // handle command KILL #860 - if (prepared == false) { + //if (prepared == false) { if (handle_command_query_kill(pkt)) { return true; } - } - if (qpo->cache_ttl>0) { + //} + if (qpo->cache_ttl>0 && ((prepare_stmt_type & ps_type_prepare_stmt) == 0)) { bool deprecate_eof_active = client_myds->myconn->options.client_flag & CLIENT_DEPRECATE_EOF; uint32_t resbuf=0; unsigned char *aa=GloQC->get( diff --git a/lib/mysql_connection.cpp b/lib/mysql_connection.cpp index fb1dd4cabe..3788287b13 100644 --- a/lib/mysql_connection.cpp +++ b/lib/mysql_connection.cpp @@ -554,11 +554,13 @@ void MySQL_Connection::update_warning_count_from_connection() { // 'mysql_thread_query_digest' is set to false, fetching that statement from the cache may still contain the digest text. // To prevent this, we will check the digest text in conjunction with 'mysql_thread_query_digest' to verify whether it // is enabled or disabled. - if (myds && myds->sess && (myds->sess->CurrentQuery.QueryParserArgs.digest_text || - (myds->sess->CurrentQuery.stmt_info && myds->sess->CurrentQuery.stmt_info->digest_text && - mysql_thread___query_digests == true))) { - const bool handle_warnings_enabled = parent->myhgc->handle_warnings_enabled(); - if (handle_warnings_enabled && mysql_errno(mysql) == 0 && mysql_warning_count(mysql) > 0) { + if (myds && myds->sess && myds->sess->CurrentQuery.QueryParserArgs.digest_text) { + const char* dig_text = myds->sess->CurrentQuery.QueryParserArgs.digest_text; + const size_t dig_len = strlen(dig_text); + // SHOW WARNINGS doesn't have any impact warning count, + // so we are replication same behaviour here + if (parent->myhgc->handle_warnings_enabled() && + (dig_len != 13 || strncasecmp(dig_text, "SHOW WARNINGS", 13) != 0)) { warning_count = mysql_warning_count(mysql); } } @@ -571,8 +573,7 @@ void MySQL_Connection::update_warning_count_from_statement() { // is enabled or disabled. if (myds && myds->sess && myds->sess->CurrentQuery.stmt_info && myds->sess->CurrentQuery.stmt_info->digest_text && mysql_thread___query_digests == true) { - const bool handle_warnings_enabled = parent->myhgc->handle_warnings_enabled(); - if (handle_warnings_enabled && mysql_stmt_warning_count(query.stmt) > 0) { + if (parent->myhgc->handle_warnings_enabled()) { warning_count = mysql_stmt_warning_count(query.stmt); } } @@ -1382,7 +1383,7 @@ MDB_ASYNC_ST MySQL_Connection::handler(short event) { if (query.stmt_result==NULL) { NEXT_IMMEDIATE(ASYNC_STMT_EXECUTE_END); } else { - update_warning_count_from_connection(); //update_warning_count_from_statement(); + update_warning_count_from_statement(); if (myds->sess->mirror==false) { if (MyRS_reuse == NULL) { MyRS = new MySQL_ResultSet(); @@ -1497,7 +1498,7 @@ MDB_ASYNC_ST MySQL_Connection::handler(short event) { NEXT_IMMEDIATE(ASYNC_STMT_EXECUTE_SUCCESSFUL); } */ - update_warning_count_from_connection(); //update_warning_count_from_statement(); + update_warning_count_from_statement(); break; // case ASYNC_STMT_EXECUTE_SUCCESSFUL: // break; @@ -2615,7 +2616,6 @@ void MySQL_Connection::ProcessQueryAndSetStatusFlags(char *query_digest_text) { // 'warning_in_hg' will be used if the next query is 'SHOW WARNINGS' or // 'SHOW COUNT(*) WARNINGS' myds->sess->warning_in_hg = myds->sess->current_hostgroup; - //warning_count = mysql_warning_count(this->mysql); // enabling multiplexing set_status(true, STATUS_MYSQL_CONNECTION_HAS_WARNINGS); } diff --git a/test/tap/tests/test_cluster_sync-t.cpp b/test/tap/tests/test_cluster_sync-t.cpp index 9e948ada8f..ace26132d0 100644 --- a/test/tap/tests/test_cluster_sync-t.cpp +++ b/test/tap/tests/test_cluster_sync-t.cpp @@ -1070,7 +1070,7 @@ int main(int, char**) { std::make_tuple(18, 2, -1, 20, "SET sql_mode = \"\"", 0, 0, 100, "", "", ""), std::make_tuple(19, 2, -1, 20, "SET sql_mode = \"\"", 0, 0, 100, "{}", "{}", "{}"), std::make_tuple(20, 0, 0, 30, "SET long_query_time = 0", 1, 0, 123, "{\"session_variables\":[\"tmp_table_size\",\"join_buffer_size\"]}", "", ""), - std::make_tuple(21, 2, -1, 50, "SET sql_mode = \"\"", 1, 0, 125, "{\"session_variables\":[\"tmp_table_size\",\"join_buffer_size\"]}", "{}", ""), + std::make_tuple(21, 2, -1, 50, "SET sql_mode = \"\"", 1, 0, 125, "{\"session_variables\":[\"tmp_table_size\",\"join_buffer_size\"]}", "{\"handle_warnings\":1}", ""), std::make_tuple(22, 3, -1, 40, "SET sql_mode = \"\"", 1, 0, 124, "{\"session_variables\":[\"tmp_table_size\",\"join_buffer_size\"]}", "", "{\"weight\": 100, \"max_connections\": 1000}") }; std::vector insert_mysql_hostgroup_attributes_queries{}; diff --git a/test/tap/tests/test_warnings-t.cpp b/test/tap/tests/test_warnings-t.cpp index 6ddc148b9c..65ed4c76d7 100644 --- a/test/tap/tests/test_warnings-t.cpp +++ b/test/tap/tests/test_warnings-t.cpp @@ -31,7 +31,12 @@ using MESSAGE = std::string; } \ } while(0) -#define MYSQL_CLEAR_RESULT(mysql) mysql_free_result(mysql_store_result(mysql)); +#define MYSQL_CLEAR_RESULT(mysql) mysql_free_result(mysql_store_result(mysql)); +#define MYSQL_CLEAR_STMT_RESULT(stmt) mysql_stmt_store_result(stmt); \ + mysql_stmt_free_result(stmt); + +#define INIT_QUERY_TEXT(QUERY, IS_SELECT) {QUERY, IS_SELECT, false} +#define INIT_QUERY_PREPARE_STMT(QUERY, IS_SELECT) {QUERY, IS_SELECT, true} enum MultiplexStatus { kNotApplicable = 0, @@ -42,8 +47,8 @@ enum MultiplexStatus { }; enum ConnectionType { - kAdmin, - kMySQL + kAdmin = 0, + kMySQL = 1 }; enum class WarningCheckType { @@ -57,6 +62,7 @@ enum class WarningCheckType { struct QueryInfo { const char* query; bool is_select; + bool prepare_stmt; }; struct WarningCheckInfo { @@ -65,13 +71,60 @@ struct WarningCheckInfo { std::vector warning_codes; }; -struct TestInfo { +struct Connection { ConnectionType conn_type; + size_t id; +}; + +struct TestInfo { + Connection conn; QueryInfo query_info; WarningCheckInfo warning_check_info; int multiplex_status; }; +#define MYSQL_CONN_DEFAULT {ConnectionType::kMySQL, 0} +#define ADMIN_CONN_DEFAULT {ConnectionType::kAdmin, 0} +#define MYSQL_CONN(ID) {ConnectionType::kMySQL, ID} +#define ADMIN_CONN(ID) {ConnectionType::kAdmin, ID} + +CommandLine cl; +std::array,2> conn_pool; + +MYSQL* get_connection(const Connection& conn, bool enable_client_deprecate_eof) { + auto& my_conn = conn_pool[conn.conn_type]; + const auto& itr = my_conn.find(conn.id); + if (itr != my_conn.end()) { + return itr->second; + } + // Initialize connection + MYSQL* proxysql = mysql_init(NULL); + if (!proxysql) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql)); + return NULL; + } + + if (enable_client_deprecate_eof) { + // enable 'CLIENT_DEPRECATE_EOF' support + proxysql->options.client_flag |= CLIENT_DEPRECATE_EOF; + } + + if (conn.conn_type == kAdmin) { + // Connnect to ProxySQL + if (!mysql_real_connect(proxysql, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql)); + return NULL; + } + } else if (conn.conn_type == kMySQL) { + // Connect to ProxySQL + if (!mysql_real_connect(proxysql, 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)); + return NULL; + } + } + my_conn[conn.id] = proxysql; + return proxysql; +} void parse_result_json_column(MYSQL_RES* result, nlohmann::json& j) { if (!result) return; @@ -89,11 +142,41 @@ int execute_query(MYSQL* proxysql, const QueryInfo& query_info) { return EXIT_SUCCESS; } +int prepare_and_execute_stmt(MYSQL* mysql, const QueryInfo& query_info, MYSQL_STMT** stmt_out) { + assert(stmt_out); + MYSQL_STMT* stmt = mysql_stmt_init(mysql); + if (!stmt) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql)); + return EXIT_FAILURE; + } + if (mysql_stmt_prepare(stmt, query_info.query, strlen(query_info.query))) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); + return EXIT_FAILURE; + } + if (mysql_stmt_execute(stmt) != 0) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); + return EXIT_FAILURE; + } + if (query_info.is_select) { + MYSQL_CLEAR_STMT_RESULT(stmt); + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + *stmt_out = stmt; + return EXIT_SUCCESS; +} + // get warning count from MySQL connection (MYSQL::warning_count) int get_warnings_count_from_connection(MYSQL* mysql) { return mysql_warning_count(mysql); } +// get warning count from statement (MYSQL_STMT::mysql_upsert_status::warning_count) +int get_warnings_count_from_statement(MYSQL_STMT* stmt) { + return mysql_stmt_warning_count(stmt); +} + // retrieve warning count through a query. This action does not clear the warning message list. int get_warnings_count(MYSQL* mysql) { MYSQL_QUERY(mysql, "SHOW COUNT(*) WARNINGS"); @@ -173,184 +256,209 @@ int check_proxysql_internal_session(MYSQL* proxysql, int exp_status) { } const std::vector mysql_variable_test = { - { ConnectionType::kAdmin, {"DELETE FROM mysql_query_rules", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL QUERY RULES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"SET mysql-handle_warnings=0", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL VARIABLES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kMySQL, {"DO 1/0", false}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kAdmin, {"SET mysql-handle_warnings=1", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL VARIABLES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, - { ConnectionType::kMySQL, {"SELECT 1" , true}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kMySQL, {"DO 1/0", false}, {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, - { ConnectionType::kMySQL, {"DO 1", false}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) } + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("DELETE FROM mysql_query_rules", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL QUERY RULES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("DELETE FROM mysql_hostgroup_attributes", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL SERVERS TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("SET mysql-handle_warnings=0", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL VARIABLES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1/0", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1/0", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("DO 1/0", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("SET mysql-handle_warnings=1", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL VARIABLES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1" , true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1/0", false), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1" , true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("DO 1/0", false), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("DO 1", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) } }; const std::vector hostgroup_attributes_test = { - { ConnectionType::kAdmin, {"SET mysql-handle_warnings=1", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL VARIABLES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"DELETE FROM mysql_hostgroup_attributes", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"INSERT INTO mysql_hostgroup_attributes (hostgroup_id, hostgroup_settings) VALUES (0, '{\"handle_warnings\":0}')", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL SERVERS TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("SET mysql-handle_warnings=1", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL VARIABLES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("DELETE FROM mysql_hostgroup_attributes", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("INSERT INTO mysql_hostgroup_attributes (hostgroup_id, hostgroup_settings) VALUES (0, '{\"handle_warnings\":0}')", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL SERVERS TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, // Hostgroup attributes take precedence and should override the global variable value for the specified hostgroup. - { ConnectionType::kMySQL, {"DO 1/0", false}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled)}, - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled)}, - { ConnectionType::kMySQL, {"DO 1", false}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kMySQL, {"SELECT 1", true}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kAdmin, {"SET mysql-handle_warnings=0", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL VARIABLES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"DELETE FROM mysql_hostgroup_attributes", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"INSERT INTO mysql_hostgroup_attributes (hostgroup_id, hostgroup_settings) VALUES (0, '{\"handle_warnings\":1}')", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL SERVERS TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kMySQL, {"DO 1/0", false}, {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) } // intentional + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1/0", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled)}, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled)}, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("DO 1/0", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled)}, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1/0", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled)}, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("DO 1", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("SET mysql-handle_warnings=0", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL VARIABLES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("DELETE FROM mysql_hostgroup_attributes", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("INSERT INTO mysql_hostgroup_attributes (hostgroup_id, hostgroup_settings) VALUES (0, '{\"handle_warnings\":1}')", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL SERVERS TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1/0", false), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("DO 1/0", false), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) } }; -const std::vector select_test = { - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, - { ConnectionType::kMySQL, {"SELECT 1" , true}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kMySQL, {"DO 1/0", false}, {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, - { ConnectionType::kMySQL, {"DO 1" , false}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) } +const std::vector random_test = { + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1" , true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1/0", false), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1" , false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SET character_set_database='latin1'", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1" , true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1" , true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("DO 1/0", false), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("DO 1" , false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SET character_set_database='latin2'", false), {WarningCheckType::kAll, 1, {1681}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1" , true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) } }; const std::vector insert_test = { - { ConnectionType::kMySQL, {"SET sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kMySQL, {"DROP DATABASE IF EXISTS testdb", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kMySQL, {"CREATE DATABASE testdb", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kMySQL, {"CREATE TABLE testdb.t1 (a TINYINT NOT NULL, b CHAR(4))", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kMySQL, {"INSERT INTO testdb.t1 VALUES(10, 'mysql'), (NULL, 'test'), (300, 'xyz')", false}, {WarningCheckType::kAll, 3, {1265,1048,1264}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, - { ConnectionType::kMySQL, {"SELECT 1", true}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kMySQL, {"DROP DATABASE IF EXISTS testdb", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kMultiplexingDisabled) } + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SET sql_mode='ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DROP DATABASE IF EXISTS testdb", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("CREATE DATABASE testdb", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("CREATE TABLE testdb.t1 (a TINYINT NOT NULL, b CHAR(4))", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("INSERT INTO testdb.t1 VALUES(10, 'mysql'), (NULL, 'test'), (300, 'xyz')", false), {WarningCheckType::kAll, 3, {1265,1048,1264}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("INSERT INTO testdb.t1 VALUES(10, 'mysql'), (NULL, 'test'), (300, 'xyz')", false), {WarningCheckType::kAll, 3, {1265,1048,1264}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DROP DATABASE IF EXISTS testdb", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kMultiplexingDisabled) } }; const std::vector query_cache_test = { - { ConnectionType::kAdmin, {"SET mysql-query_cache_handle_warnings=0", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL VARIABLES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"DELETE FROM mysql_query_rules", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"INSERT INTO mysql_query_rules (rule_id,active,match_digest,cache_ttl,apply) VALUES (1,1,'SELECT ?/?',60000,1)", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL QUERY RULES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"PROXYSQL FLUSH QUERY CACHE", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("SET mysql-query_cache_handle_warnings=0", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL VARIABLES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("DELETE FROM mysql_query_rules", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("INSERT INTO mysql_query_rules (rule_id,active,match_digest,cache_ttl,apply) VALUES (1,1,'SELECT ?/?',60000,1)", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL QUERY RULES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("PROXYSQL FLUSH QUERY CACHE", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, // this entry should not be saved in cache - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, - { ConnectionType::kMySQL, {"SELECT 1", true}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kAdmin, {"SET mysql-query_cache_handle_warnings=1", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL VARIABLES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + // to check if prepare statement conflicts with cache + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + // { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("SET mysql-query_cache_handle_warnings=1", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL VARIABLES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, // resultset will be retrived from cache, with warning count zero - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kAdmin, {"DELETE FROM mysql_query_rules", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL QUERY RULES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"PROXYSQL FLUSH QUERY CACHE", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) } + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + // to check if prepare statement conflicts with cache + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("DELETE FROM mysql_query_rules", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL QUERY RULES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("PROXYSQL FLUSH QUERY CACHE", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) } }; const std::vector query_digest_test = { - { ConnectionType::kAdmin, {"SET mysql-query_digests='false'", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL VARIABLES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kAdmin, {"SET mysql-query_digests='true'", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL VARIABLES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) } + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("SET mysql-query_digests='false'", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL VARIABLES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1/0", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1/0", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("DO 1/0", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("SET mysql-query_digests='true'", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL VARIABLES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1/0", false), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) } }; const std::vector warning_log_test = { - { ConnectionType::kAdmin, {"SET mysql-log_mysql_warnings_enabled='true'", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL VARIABLES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, - { ConnectionType::kMySQL, {"SELECT 1", true}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, - { ConnectionType::kAdmin, {"SET mysql-log_mysql_warnings_enabled='false'", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, - { ConnectionType::kAdmin, {"LOAD MYSQL VARIABLES TO RUNTIME", false}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) } + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("SET mysql-log_mysql_warnings_enabled='true'", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL VARIABLES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1/0", false), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("DO 1", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_PREPARE_STMT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingDisabled) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("SET mysql-log_mysql_warnings_enabled='false'", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) }, + { ADMIN_CONN_DEFAULT, INIT_QUERY_TEXT("LOAD MYSQL VARIABLES TO RUNTIME", false), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kNotApplicable) } }; const std::vector multiplexing_test = { - { ConnectionType::kMySQL, {"SELECT @@sql_mode", true}, {WarningCheckType::kNotApplicable}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables) }, - { ConnectionType::kMySQL, {"SELECT 1/0", true}, {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables | MultiplexStatus::kHasWarnings) }, - { ConnectionType::kMySQL, {"SELECT 1", true}, {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables) } + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT @@sql_mode", true), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables | MultiplexStatus::kHasWarnings) }, + { MYSQL_CONN_DEFAULT, INIT_QUERY_TEXT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables) }, + { MYSQL_CONN(1), INIT_QUERY_TEXT("SELECT @@sql_mode", true), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables)}, + { MYSQL_CONN(1), INIT_QUERY_TEXT("DO 1/0", false), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables | MultiplexStatus::kHasWarnings)}, + { MYSQL_CONN(1), INIT_QUERY_TEXT("DO 1", false), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables)}, + { MYSQL_CONN(2), INIT_QUERY_PREPARE_STMT("SELECT @@sql_mode", true), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables)}, + { MYSQL_CONN(2), INIT_QUERY_PREPARE_STMT("SELECT 1/0", true), {WarningCheckType::kAll, 1, {1365}}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables | MultiplexStatus::kHasWarnings)}, + { MYSQL_CONN(2), INIT_QUERY_PREPARE_STMT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables) }, + { MYSQL_CONN(3), INIT_QUERY_PREPARE_STMT("SET @test_variable = 44", true), {WarningCheckType::kNotApplicable}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables)}, + { MYSQL_CONN(3), INIT_QUERY_PREPARE_STMT("SELECT 1", true), {WarningCheckType::kAll, 0}, (MultiplexStatus::kMultiplexingEnabled | MultiplexStatus::kUserVariables) } }; #define IS_BIT_MASK_SET(variable,flag) ((variable & static_cast(flag)) == static_cast(flag)) -int main(int argc, char** argv) { +// base case +size_t check_count() { return 0; } - CommandLine cl; +template +size_t check_count(First&& first, Rest&&... rest) { - if (cl.getEnv()) { - diag("Failed to get the required environmental variables."); - return -1; - } - - plan((20 + 6) + // mysql variable test: 20 warning checks, 6 multiplex status checks - (20 + 6) + // hostgroup attributes test: 20 warning checks, 6 multiplex status checks - (14 + 4) + // select test: 14 warning checks, 4 multiplex status checks - (9 + 4) + // insert test: 9 warning checks, 4 multiplex status checks - (3 + 1) + // query digest test: 3 warning checks, 1 multiplex status checks - (18 + 5) + // query cache test: 18 warning checks, 5 multiplex status checks - (7 + 2) + // warning log test: 7 warning checks, 2 multiplex status checks - (7 + 3)); // multiplexing test: 7 warning checks, 3 multiplex status checks - - // Initialize Admin connection - MYSQL* proxysql_admin = mysql_init(NULL); - if (!proxysql_admin) { - fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin)); - return -1; - } - // Connnect to ProxySQL Admin - if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_username, 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 exit_status(); - } - - // Initialize ProxySQL connection - MYSQL* proxysql = mysql_init(NULL); - if (!proxysql) { - fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql)); - return exit_status(); - } - - // Connect to ProxySQL - if (!mysql_real_connect(proxysql, 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)); - return exit_status(); - } - - std::vector>> all_tests(8); - - all_tests[0].first = "MYSQL VARIABLE (mysql-handle_warnings)"; - all_tests[0].second.insert(all_tests[0].second.end(), mysql_variable_test.begin(), mysql_variable_test.end()); - - all_tests[1].first = "HOSTGROUP ATTRIBUTES (handle_warnings)"; - all_tests[1].second.insert(all_tests[1].second.end(), hostgroup_attributes_test.begin(), hostgroup_attributes_test.end()); + size_t count = 0; - all_tests[2].first = "SELECT"; - all_tests[2].second.insert(all_tests[2].second.end(), select_test.begin(), select_test.end()); - - all_tests[3].first = "INSERT"; - all_tests[3].second.insert(all_tests[3].second.end(), insert_test.begin(), insert_test.end()); - - all_tests[4].first = "QUERY_DIGEST"; - all_tests[4].second.insert(all_tests[4].second.end(), query_digest_test.begin(), query_digest_test.end()); - - all_tests[5].first = "QUERY_CACHE"; - all_tests[5].second.insert(all_tests[5].second.end(), query_cache_test.begin(), query_cache_test.end()); + for (const auto& val : first) { + if (val.warning_check_info.type != WarningCheckType::kNotApplicable) { + if (val.warning_check_info.type == WarningCheckType::kAll) + count += 3; + else + count += 1; + count += val.warning_check_info.warning_codes.size(); + } + if (val.multiplex_status != 0) + count += 1; + } + return (count + check_count(rest...)); +} - all_tests[6].first = "WARNING_LOGS"; - all_tests[6].second.insert(all_tests[6].second.end(), warning_log_test.begin(), warning_log_test.end()); +template +constexpr size_t test_size(Args&&... args) { + return sizeof...(args); +} - all_tests[7].first = "MULTIPLEXING"; - all_tests[7].second.insert(all_tests[7].second.end(), multiplexing_test.begin(), multiplexing_test.end()); +#define TESTS_COMBINED mysql_variable_test, hostgroup_attributes_test, random_test, insert_test, query_digest_test, \ + query_cache_test, warning_log_test, multiplexing_test +void execute_tests(const std::vector>>& all_tests, bool enable_client_deprecate_eof) { for (const auto& test : all_tests) { - diag("Executing [%s] test...", test.first); + diag("Executing [%s] test... [CLIENT_DEPRECATE_EOF=%s]", test.first, (enable_client_deprecate_eof ? "TRUE" : "FALSE")); for (const auto& test_info : test.second) { - MYSQL* mysql = (test_info.conn_type == ConnectionType::kMySQL ? proxysql : proxysql_admin); - - if (execute_query(mysql, test_info.query_info) == EXIT_FAILURE) + MYSQL_STMT* stmt = nullptr; + MYSQL* mysql = get_connection(test_info.conn, enable_client_deprecate_eof); + if (!mysql) { goto __exit; + } + if (test_info.query_info.prepare_stmt) { + if (prepare_and_execute_stmt(mysql, test_info.query_info, &stmt) == EXIT_FAILURE) + goto __exit; + } else { + if (execute_query(mysql, test_info.query_info) == EXIT_FAILURE) + goto __exit; + } const int check_type = static_cast(test_info.warning_check_info.type); if (IS_BIT_MASK_SET(check_type, WarningCheckType::kConnection)) { - const int count = get_warnings_count_from_connection(mysql); + int count = get_warnings_count_from_connection(mysql); + if (test_info.query_info.prepare_stmt) { + count &= get_warnings_count_from_statement(stmt); + } ok((count == test_info.warning_check_info.warning_count), "Connection warning count should match. Expected count:'%d' Actual count:'%d'", test_info.warning_check_info.warning_count, count); } if (IS_BIT_MASK_SET(check_type, WarningCheckType::kCountQuery)) { @@ -379,15 +487,76 @@ int main(int argc, char** argv) { } if (test_info.multiplex_status != MultiplexStatus::kNotApplicable) { - if (check_proxysql_internal_session(mysql, test_info.multiplex_status) != EXIT_SUCCESS) + if (check_proxysql_internal_session(mysql, test_info.multiplex_status) != EXIT_SUCCESS) { + if (stmt) + mysql_stmt_close(stmt); goto __exit; + } } + + if (stmt) + mysql_stmt_close(stmt); } } __exit: - mysql_close(proxysql); - mysql_close(proxysql_admin); + for (const auto& mysql_conn : conn_pool[kAdmin]) { + mysql_close(mysql_conn.second); + } + conn_pool[kAdmin].clear(); + for (const auto& mysql_conn : conn_pool[kMySQL]) { + mysql_close(mysql_conn.second); + } + conn_pool[kMySQL].clear(); +} + +int main(int argc, char** argv) { + + if (cl.getEnv()) { + diag("Failed to get the required environmental variables."); + return -1; + } + + plan(check_count(TESTS_COMBINED)*2); // also check with client_deprecate_eof flag + + /*plan((20 + 6) + // mysql variable test: 20 warning checks, 6 multiplex status checks + (20 + 6) + // hostgroup attributes test: 20 warning checks, 6 multiplex status checks + (14 + 4) + // random test: 14 warning checks, 4 multiplex status checks + (9 + 4) + // insert test: 9 warning checks, 4 multiplex status checks + (3 + 1) + // query digest test: 3 warning checks, 1 multiplex status checks + (18 + 5) + // query cache test: 18 warning checks, 5 multiplex status checks + (7 + 2) + // warning log test: 7 warning checks, 2 multiplex status checks + (7 + 3)); // multiplexing test: 7 warning checks, 3 multiplex status checks + */ + + std::vector>> all_tests(test_size(TESTS_COMBINED)); + + all_tests[0].first = "MYSQL VARIABLE (mysql-handle_warnings)"; + all_tests[0].second.insert(all_tests[0].second.end(), mysql_variable_test.begin(), mysql_variable_test.end()); + + all_tests[1].first = "HOSTGROUP ATTRIBUTES (handle_warnings)"; + all_tests[1].second.insert(all_tests[1].second.end(), hostgroup_attributes_test.begin(), hostgroup_attributes_test.end()); + + all_tests[2].first = "RANDOM"; + all_tests[2].second.insert(all_tests[2].second.end(), random_test.begin(), random_test.end()); + + all_tests[3].first = "INSERT"; + all_tests[3].second.insert(all_tests[3].second.end(), insert_test.begin(), insert_test.end()); + + all_tests[4].first = "QUERY_DIGEST"; + all_tests[4].second.insert(all_tests[4].second.end(), query_digest_test.begin(), query_digest_test.end()); + + all_tests[5].first = "QUERY_CACHE"; + all_tests[5].second.insert(all_tests[5].second.end(), query_cache_test.begin(), query_cache_test.end()); + + all_tests[6].first = "WARNING_LOGS"; + all_tests[6].second.insert(all_tests[6].second.end(), warning_log_test.begin(), warning_log_test.end()); + + all_tests[7].first = "MULTIPLEXING"; + all_tests[7].second.insert(all_tests[7].second.end(), multiplexing_test.begin(), multiplexing_test.end()); + + execute_tests(all_tests, false); + execute_tests(all_tests, true); return exit_status(); }