diff --git a/lib/Query_Cache.cpp b/lib/Query_Cache.cpp index de2dd7152..5a70626c9 100644 --- a/lib/Query_Cache.cpp +++ b/lib/Query_Cache.cpp @@ -515,10 +515,34 @@ unsigned char* eof_to_ok_packet(QC_entry_t* entry) { // Initialize affected_rows and last_insert_id to zero memset(vp, 0, 2); vp += 2; - // Copy the warning an status flags - memcpy(vp, it, 4); + // Extract warning flags and status from 'EOF_packet' + char* eof_packet = entry->value + entry->row_eof_pkt_offset; + eof_packet += sizeof(mysql_hdr); + // Skip the '0xFE EOF packet header' + eof_packet += 1; + uint16_t warnings; + memcpy(&warnings, eof_packet, sizeof(uint16_t)); + eof_packet += 2; + uint16_t status_flags; + memcpy(&status_flags, eof_packet, sizeof(uint16_t)); + // Copy warnings an status flags + memcpy(vp, &status_flags, sizeof(uint16_t)); + vp += 2; + memcpy(vp, &warnings, sizeof(uint16_t)); // ======================================= + // Decrement ids after the first EOF + unsigned char* dp = result + entry->column_eof_pkt_offset; + mysql_hdr decrement_hdr; + for (;;) { + memcpy(&decrement_hdr, dp, sizeof(mysql_hdr)); + decrement_hdr.pkt_id--; + memcpy(dp, &decrement_hdr, sizeof(mysql_hdr)); + dp += sizeof(mysql_hdr) + decrement_hdr.pkt_length; + if (dp >= vp) + break; + } + return result; } @@ -543,9 +567,11 @@ unsigned char* ok_to_eof_packet(QC_entry_t* entry) { ok_packet += sizeof(mysql_hdr); // Skip the 'OK packet header', 'affected_rows' and 'last_insert_id' ok_packet += 3; - uint16_t status_flags = *reinterpret_cast(ok_packet); + uint16_t status_flags; + memcpy(&status_flags, ok_packet, sizeof(uint16_t)); ok_packet += 2; - uint16_t warnings = *reinterpret_cast(ok_packet); + uint16_t warnings; + memcpy(&warnings, ok_packet, sizeof(uint16_t)); // Find the spot in which the first EOF needs to be placed it += sizeof(mysql_hdr); @@ -575,9 +601,9 @@ unsigned char* ok_to_eof_packet(QC_entry_t* entry) { // Write 'column_eof_packet' contents *vp = 0xfe; vp++; - *reinterpret_cast(vp) = warnings; + memcpy(vp, &warnings, sizeof(uint16_t)); vp += 2; - *reinterpret_cast(vp) = status_flags; + memcpy(vp, &status_flags, sizeof(uint16_t)); vp += 2; // Find the OK packet @@ -597,9 +623,9 @@ unsigned char* ok_to_eof_packet(QC_entry_t* entry) { *vp = 0xfe; vp++; - *reinterpret_cast(vp) = warnings; + memcpy(vp, &warnings, sizeof(uint16_t)); vp += 2; - *reinterpret_cast(vp) = status_flags; + memcpy(vp, &status_flags, sizeof(uint16_t)); break; } else { // Increment the package id by one due to 'column_eof_packet' diff --git a/test/tap/tests_with_deps/deprecate_eof_support/Makefile b/test/tap/tests_with_deps/deprecate_eof_support/Makefile index f95c9ce81..6e7a3d819 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/Makefile +++ b/test/tap/tests_with_deps/deprecate_eof_support/Makefile @@ -62,12 +62,12 @@ eof_packet_mixed_queries-t: ok_packet_mixed_queries-t $(TESTS_DEPS) fwd_eof_query: fwd_eof_query.cpp $(TESTS_DEPS) $(CXX) -DNON_EOF_SUPPORT -DDEBUG fwd_eof_query.cpp $(OPT) -std=c++11 -I$(JSON_IDIR) -I$(TAP_LIBDIR) -I $(MARIADB_TEST_DEP)/include/ -I $(IDIR) -L$(TAP_LIBDIR) -L$(TAP_DEPS_LIBS) -L $(MARIADB_TEST_DEP)/libmariadb $(MYLIBS) -L$(SSL_LDIR) -ltap -ldl -o fwd_eof_query -DGITVERSION=\"$(GIT_VERSION)\" -fwd_eof_ok_query: fwd_eof_query.cpp $(TESTS_DEPS) - $(CXX) -DDEBUG fwd_eof_query.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 -I$(TAP_LIBDIR) -L$(TAP_LIBDIR) $(MYLIBS) -L$(SSL_LDIR) -ltap -Wl,--no-as-needed -ldl -lpthread -o fwd_eof_ok_query -DGITVERSION=\"$(GIT_VERSION)\" +#fwd_eof_ok_query: fwd_eof_query.cpp $(TESTS_DEPS) +# $(CXX) -DDEBUG fwd_eof_query.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 -I$(TAP_LIBDIR) -L$(TAP_LIBDIR) $(MYLIBS) -L$(SSL_LDIR) -ltap -Wl,--no-as-needed -ldl -lpthread -o fwd_eof_ok_query -DGITVERSION=\"$(GIT_VERSION)\" # NOTE: Compilation with 'libmysql' instead of 'libmariadb' client to confirm packet sequence id isn't check by 'libmariadb' -# fwd_eof_ok_query: fwd_eof_ok_query.cpp $(TAP_LIBDIR)/libtap.a -# $(CXX) -DDEBUG fwd_eof_ok_query.cpp $(OPT) -std=c++11 -I$(JSON_IDIR) -I$(TAP_LIBDIR) -I /usr/include/mysql/ -I $(IDIR) -L$(TAP_LIBDIR) -L$(TAP_DEPS_LIBS) -L /usr/lib/x86_64-linux-gnu/ -lmysqlclient -ltap -ldl -o fwd_eof_ok_query -DGITVERSION=\"$(GIT_VERSION)\" +fwd_eof_ok_query: fwd_eof_query.cpp $(TAP_LIBDIR)/libtap.a + $(CXX) -DDEBUG fwd_eof_query.cpp $(OPT) -std=c++11 -I$(JSON_IDIR) -I$(TAP_LIBDIR) -I /usr/include/mysql/ -I $(IDIR) -L$(TAP_LIBDIR) -L$(TAP_DEPS_LIBS) -L /usr/lib/x86_64-linux-gnu/ -lmysqlclient -ltap -ldl -o fwd_eof_ok_query -DGITVERSION=\"$(GIT_VERSION)\" deprecate_eof_cache-t: deprecate_eof_cache-t.cpp $(TESTS_DEPS) $(CXX) -DDEBUG deprecate_eof_cache-t.cpp $(OPT) -std=c++11 -I$(JSON_IDIR) -I$(TAP_LIBDIR) -I $(MARIADB_TEST_DEP)/include/ -I $(IDIR) -L$(TAP_LIBDIR) -L$(TAP_DEPS_LIBS) -L$(MARIADB_TEST_DEP)/libmariadb -L$(SSL_LDIR) -L$(PROXYLDIR) -ltap $(MYLIBS) -lproxysql -ldl -o deprecate_eof_cache-t -DGITVERSION=\"$(GIT_VERSION)\" diff --git a/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp b/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp index 7ca331d42..8d0bd6e48 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp @@ -141,9 +141,10 @@ int main(int argc, char** argv) { // Load query rules to runtime MYSQL_QUERY(proxy_admin, "LOAD MYSQL QUERY RULES TO RUNTIME"); - for (auto id = 0; id < c_operations; id++) { + for (auto i = 0; i < c_operations; i++) { int rnd_op = rand() % c_operations; + const auto id = i + 1; const std::string& t_select_query = queries[0]; std::string select_query {}; string_format(t_select_query, select_query, id); @@ -193,11 +194,49 @@ int main(int argc, char** argv) { return exit_status(); } + nlohmann::json eof_query_res_json = nlohmann::json::parse(eof_query_res); + nlohmann::json ok_query_res_json = nlohmann::json::parse(ok_query_res); + + const std::string ok_res_id = ok_query_res_json["Result"][0]["id"]; + ok( + ok_res_id == std::to_string(id), + "EOF to OK -> inserted id: %d // received id: %s", + id, + ok_res_id.c_str() + ); + + const std::string ok_res_c = ok_query_res_json["Result"][0]["c"]; + ok( + ok_res_c == stored_pairs[i].first, + "EOF to OK -> inserted c: %s // received c: %s", + stored_pairs[i].first.c_str(), + ok_res_c.c_str() + ); + + const std::string ok_res_pad = ok_query_res_json["Result"][0]["pad"]; + ok( + ok_res_pad == stored_pairs[i].second, + "EOF to OK -> inserted pad: %s // received pad: %s", + stored_pairs[i].second.c_str(), + ok_res_pad.c_str() + ); + + uint32_t eof_res_status = eof_query_res_json["Status"]; + uint32_t ok_res_status = ok_query_res_json["Status"]; + ok( + eof_res_status == ok_res_status, + "EOF to OK -> EOF received status: %d // OK received status: %d", + eof_res_status, + ok_res_status + ); + + uint32_t eof_res_warnings = eof_query_res_json["Warnings"]; + uint32_t ok_res_warnings = ok_query_res_json["Warnings"]; ok( - eof_query_res == ok_query_res, - "EOF to OK: ['eof_query_res': %s] should match ['ok_query_res': %s]", - eof_query_res.c_str(), - ok_query_res.c_str() + eof_res_warnings == ok_res_warnings, + "EOF to OK -> EOF received warnings: %d // OK received warnings: %d", + eof_res_warnings, + ok_res_warnings ); // Wait for invalidation of query_cache @@ -218,11 +257,49 @@ int main(int argc, char** argv) { return exit_status(); } + ok_query_res_json = nlohmann::json::parse(ok_query_res); + eof_query_res_json = nlohmann::json::parse(eof_query_res); + + const std::string eof_res_id = eof_query_res_json["Result"][0]["id"]; + ok( + eof_res_id == std::to_string(id), + "OK to EOF -> inserted id: %d // received id: %s", + id, + eof_res_id.c_str() + ); + + const std::string eof_res_c = eof_query_res_json["Result"][0]["c"]; + ok( + eof_res_c == stored_pairs[i].first, + "OK to EOF -> inserted c: %s // received c: %s", + stored_pairs[i].first.c_str(), + eof_res_c.c_str() + ); + + const std::string eof_res_pad = eof_query_res_json["Result"][0]["pad"]; + ok( + eof_res_pad == stored_pairs[i].second, + "OK to EOF -> inserted pad: %s // received pad: %s", + stored_pairs[i].second.c_str(), + eof_res_pad.c_str() + ); + + ok_res_status = ok_query_res_json["Status"]; + eof_res_status = eof_query_res_json["Status"]; + ok( + ok_res_status == eof_res_status, + "OK to EOF -> OK received status: %d // EOF received status: %d", + ok_res_status, + eof_res_status + ); + + ok_res_warnings = ok_query_res_json["Warnings"]; + eof_res_warnings = eof_query_res_json["Warnings"]; ok( - eof_query_res == ok_query_res, - "OK to EOF: ['eof_query_res': %s] should match ['ok_query_res': %s]", - eof_query_res.c_str(), - ok_query_res.c_str() + ok_res_warnings == eof_res_warnings, + "OK to EOF -> OK received warnings: %d // EOF received warnings: %d", + ok_res_warnings, + eof_res_warnings ); } diff --git a/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp b/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp index 0e7928812..6931f811c 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp @@ -246,6 +246,9 @@ int main(int argc, char** argv) { MYSQL_QUERY(proxy, "/* create_new_connection=1 */ DO 1"); } + // Impose a timeout to avoid race conditions + wait_for_backend_conns(admin, "ConnFree", 50, 1); + // Check there are 'N' backend connections uint32_t cur_free_conns = 0; int get_conns_err = get_cur_backend_conns(admin, "ConnFree", cur_free_conns); diff --git a/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp b/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp index 8c232d6a6..1c8b61613 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp @@ -12,7 +12,6 @@ #include "tap.h" #include "command_line.h" -#include "utils.h" #include "json.hpp" @@ -114,14 +113,14 @@ int main(int argc, char** argv) { if (!mysql_real_connect(proxy, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) { std::string err_msg { "MySQL Error:" + std::string { mysql_error(proxy) }+ "" }; - std::cerr << "{ Code: Err, Result: " << err_msg << " }"; + std::cerr << "{ \"Code\": \"Err\", \"Result\": \"" << err_msg << "\" }"; return -1; } int query_res = mysql_query(proxy, query.c_str()); if (query_res != 0) { std::string err_msg { "MySQL Error:" + std::string { mysql_error(proxy) }+ "" }; - std::cerr << "{ Code: Err, Result: " << err_msg << " }"; + std::cerr << "{ \"Code\": \"Err\", \"Result\": \"" << err_msg << "\" }"; return -1; } @@ -131,19 +130,21 @@ int main(int argc, char** argv) { if (select_res != NULL) { json j_res {}; MySQL_result_to_JSON(select_res, j_res); - std::cout << "{ Code: OK, Result: " << j_res.dump() << " }"; + std::cout << "{ \"Code\": \"OK\", \"Result\": " << j_res.dump() + << ", \"Status\": " << proxy->server_status + << ", \"Warnings\": " << mysql_warning_count(proxy) << " }"; } else { std::string err_msg { "MySQL Error: " + std::string { mysql_error(proxy) }+ "" }; - std::cerr << "{ Code: Err, Result: " << err_msg << " }"; + std::cerr << "{ \"Code\": \"Err\", \"Result\": \"" << err_msg << "\" }"; res_code = -1; } mysql_free_result(select_res); } else { std::string err_msg { "MySQL Error:" + std::string { mysql_error(proxy) }+ "" }; - std::cerr << "{ Code: OK, Result: 0 }"; + std::cerr << "{ \"Code\": \"OK\", \"Result\": 0 }"; } mysql_close(proxy);