From 8bfdf163c4ae7016c8ed8bc7635497d0a20f33fc Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Fri, 24 Nov 2023 13:08:49 +0500 Subject: [PATCH] Overriding some of the mariadb APIs to extract the warning count and print it in the log. This override will apply to all TAP tests, except when the TAP test is linked with the MySQL client library (LIBMYSQL_HELPER defined). --- test/tap/tap/utils.cpp | 144 +++++++++++++++++++++++++++++++++++++++++ test/tap/tap/utils.h | 35 ++++++++++ 2 files changed, 179 insertions(+) diff --git a/test/tap/tap/utils.cpp b/test/tap/tap/utils.cpp index f5fc3354c8..8ee7d1f6b8 100644 --- a/test/tap/tap/utils.cpp +++ b/test/tap/tap/utils.cpp @@ -31,6 +31,150 @@ using std::vector; using std::to_string; using nlohmann::json; +thread_local std::vector mysql_conn; +thread_local std::vector> last_query_executed; + +thread_local std::vector mysql_stmt; +thread_local std::vector> last_stmt_executed; + +MYSQL* mysql_init_override(MYSQL* mysql, const char* file, int line) { + MYSQL* result = (*real_mysql_init)(mysql); + if (mysql_conn.capacity() == 0) { + fprintf(stdout, ">> [mysql_init] Override functions attached <<\n"); + mysql_conn.reserve(64); + last_query_executed.reserve(64); + } + return result; +} + +int mysql_query_override(MYSQL* mysql, const char* query, const char* file, int line) { + const int result = (*real_mysql_query)(mysql, query); + if (result == 0) { + mysql_conn.emplace_back(mysql); + last_query_executed.emplace_back(strdup(query),&std::free); + if (mysql_errno(mysql) == 0 && mysql_field_count(mysql) == 0 && mysql_warning_count(mysql) > 0) { + fprintf(stdout, "File %s, Line %d, [mysql_query] A warning was generated during the execution of the query:'%s', warning count:%d\n", + file, line, query, mysql_warning_count(mysql)); + } + } + return result; +} + +MYSQL_RES* mysql_store_result_override(MYSQL* mysql, const char* file, int line) { + MYSQL_RES* result = (*real_mysql_store_result)(mysql); + if (mysql_errno(mysql) == 0 && mysql_warning_count(mysql) > 0) { + size_t idx = -1; + for (size_t i = 0; i < mysql_conn.size(); i++) { + if (mysql_conn[i] == mysql) { + idx = i; + break; + } + } + fprintf(stdout, "File %s, Line %d, [mysql_store_result] A warning was generated during the execution of the query:'%s', warning count:%d\n", + file, line, (idx != -1 ? last_query_executed[idx].get() : ""), mysql_warning_count(mysql)); + } + return result; +} + +void mysql_close_override(MYSQL* mysql, const char* file, int line) { + size_t idx = -1; + for (size_t i = 0; i < mysql_conn.size(); i++) { + if (mysql_conn[i] == mysql) + idx = i; + break; + } + if (idx != -1) { + if (idx != mysql_conn.size() - 1) { + mysql_conn[idx] = mysql_conn.back(); + last_query_executed[idx] = std::move(last_query_executed.back()); + } + mysql_conn.pop_back(); + last_query_executed.pop_back(); + } + (*real_mysql_close)(mysql); +} + +MYSQL_STMT* mysql_stmt_init_override(MYSQL* mysql, const char* file, int line) { + MYSQL_STMT* result = (*real_mysql_stmt_init)(mysql); + if (mysql_stmt.capacity() == 0) { + fprintf(stdout, ">> [mysql_stmt_init] Override functions attached << \n"); + mysql_stmt.reserve(64); + last_stmt_executed.reserve(64); + } + return result; +} + +int mysql_stmt_prepare_override(MYSQL_STMT* stmt, const char* stmt_str, unsigned long length, const char* file, int line) { + const int result = (*real_mysql_stmt_prepare)(stmt, stmt_str, length); + if (result == 0) { + mysql_stmt.emplace_back(stmt); + last_stmt_executed.emplace_back(strdup(stmt_str), &std::free); + // mysql_stmt_warning_count is not available in MySQL connector + if (mysql_stmt_errno(stmt) == 0 && /*mysql_stmt_warning_count(stmt)*/mysql_warning_count(stmt->mysql) > 0) { + fprintf(stdout, "File %s, Line %d, [mysql_stmt_prepare] A warning was generated during the execution of the query:'%s', warning count:%d\n", + file, line, stmt_str, /*mysql_stmt_warning_count(stmt)*/mysql_warning_count(stmt->mysql)); + } + } + return result; +} + +int mysql_stmt_execute_override(MYSQL_STMT* stmt, const char* file, int line) { + const int result = (*real_mysql_stmt_execute)(stmt); + if (result == 0) { + // mysql_stmt_warning_count is not available in MySQL connector + if (mysql_stmt_errno(stmt) == 0 && mysql_stmt_field_count(stmt) == 0 && + /*mysql_stmt_warning_count(stmt)*/mysql_warning_count(stmt->mysql) > 0) { + size_t idx = -1; + for (size_t i = 0; i < mysql_stmt.size(); i++) { + if (mysql_stmt[i] == stmt) { + idx = i; + break; + } + } + fprintf(stdout, "File %s, Line %d, [mysql_stmt_execute] A warning was generated during the execution of the query:'%s', warning count:%d\n", + file, line, (idx != -1 ? last_stmt_executed[idx].get() : ""), /*mysql_stmt_warning_count(stmt)*/mysql_warning_count(stmt->mysql)); + } + } + return result; +} + +int mysql_stmt_store_result_override(MYSQL_STMT* stmt, const char* file, int line) { + const int result = (*real_mysql_stmt_store_result)(stmt); + if (result == 0) { + // mysql_stmt_warning_count is not available in MySQL connector + if (mysql_stmt_errno(stmt) == 0 && /*mysql_stmt_warning_count(stmt)*/mysql_warning_count(stmt->mysql) > 0) { + size_t idx = -1; + for (size_t i = 0; i < mysql_stmt.size(); i++) { + if (mysql_stmt[i] == stmt) { + idx = i; + break; + } + } + fprintf(stdout, "File %s, Line %d, [mysql_stmt_store_result] A warning was generated during the execution of the query:'%s', warning count:%d\n", + file, line, (idx != -1 ? last_stmt_executed[idx].get() : ""), /*mysql_stmt_warning_count(stmt)*/mysql_warning_count(stmt->mysql)); + } + } + return result; +} + +my_bool mysql_stmt_close_override(MYSQL_STMT* stmt, const char* file, int line) { + size_t idx = -1; + for (size_t i = 0; i < mysql_stmt.size(); i++) { + if (mysql_stmt[i] == stmt) + idx = i; + break; + } + if (idx != -1) { + if (idx != mysql_stmt.size() - 1) { + mysql_stmt[idx] = mysql_stmt.back(); + last_stmt_executed[idx] = std::move(last_stmt_executed.back()); + } + mysql_stmt.pop_back(); + last_stmt_executed.pop_back(); + } + return (*real_mysql_stmt_close)(stmt); +} + std::size_t count_matches(const string& str, const string& substr) { std::size_t result = 0; std::size_t pos = 0; diff --git a/test/tap/tap/utils.h b/test/tap/tap/utils.h index da13c69e8f..d9ff6a81a5 100644 --- a/test/tap/tap/utils.h +++ b/test/tap/tap/utils.h @@ -16,6 +16,41 @@ #include "command_line.h" #include "json.hpp" +#ifndef LIBMYSQL_HELPER +/* We are overriding some of the mariadb APIs to extract the warning count and print it in the log. + This override will apply to all TAP tests, except when the TAP test is linked with the MySQL client library (LIBMYSQL_HELPER defined). +*/ +static MYSQL* (*real_mysql_init)(MYSQL* mysql) = &mysql_init; +static int (*real_mysql_query)(MYSQL* mysql, const char* query) = &mysql_query; +static MYSQL_RES* (*real_mysql_store_result)(MYSQL* mysql) = &mysql_store_result; +static void (*real_mysql_close)(MYSQL* mysql) = &mysql_close; +static MYSQL_STMT* (*real_mysql_stmt_init)(MYSQL* mysql) = &mysql_stmt_init; +static int (*real_mysql_stmt_prepare)(MYSQL_STMT* stmt, const char* stmt_str, unsigned long length) = &mysql_stmt_prepare; +static int (*real_mysql_stmt_execute)(MYSQL_STMT* stmt) = &mysql_stmt_execute; +static int (*real_mysql_stmt_store_result)(MYSQL_STMT* stmt) = &mysql_stmt_store_result; +static my_bool (*real_mysql_stmt_close)(MYSQL_STMT* stmt) = &mysql_stmt_close; + +MYSQL* mysql_init_override(MYSQL* mysql, const char* file, int line); +int mysql_query_override(MYSQL* mysql, const char* query, const char* file, int line); +MYSQL_RES* mysql_store_result_override(MYSQL* mysql, const char* file, int line); +void mysql_close_override(MYSQL* mysql, const char* file, int line); +MYSQL_STMT* mysql_stmt_init_override(MYSQL* mysql, const char* file, int line); +int mysql_stmt_prepare_override(MYSQL_STMT* stmt, const char* stmt_str, unsigned long length, const char* file, int line); +int mysql_stmt_execute_override(MYSQL_STMT* stmt, const char* file, int line); +int mysql_stmt_store_result_override(MYSQL_STMT* stmt, const char* file, int line); +my_bool mysql_stmt_close_override(MYSQL_STMT* stmt, const char* file, int line); + +#define mysql_init(mysql) mysql_init_override(mysql,__FILE__,__LINE__) +#define mysql_query(mysql,query) mysql_query_override(mysql,query,__FILE__,__LINE__) +#define mysql_store_result(mysql) mysql_store_result_override(mysql,__FILE__,__LINE__) +#define mysql_close(mysql) mysql_close_override(mysql,__FILE__,__LINE__) +#define mysql_stmt_init(mysql) mysql_stmt_init_override(mysql,__FILE__,__LINE__) +#define mysql_stmt_prepare(stmt,stmt_str,length) mysql_stmt_prepare_override(stmt,stmt_str,length,__FILE__,__LINE__) +#define mysql_stmt_execute(stmt) mysql_stmt_execute_override(stmt,__FILE__,__LINE__) +#define mysql_stmt_store_result(stmt) mysql_stmt_store_result_override(stmt,__FILE__,__LINE__) +#define mysql_stmt_close(stmt) mysql_stmt_close_override(stmt,__FILE__,__LINE__) +#endif + inline std::string get_formatted_time() { time_t __timer; char __buffer[30];