|
|
|
|
@ -25,14 +25,16 @@ using LEVEL = std::string;
|
|
|
|
|
using CODE = int;
|
|
|
|
|
using MESSAGE = std::string;
|
|
|
|
|
|
|
|
|
|
#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 MYSQL_CLEAR_RESULT(mysql) mysql_free_result(mysql_store_result(mysql))
|
|
|
|
|
#define MYSQL_CLEAR_STMT_RESULT(stmt) do { \
|
|
|
|
|
mysql_stmt_store_result(stmt); \
|
|
|
|
|
mysql_stmt_free_result(stmt); \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
#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 {
|
|
|
|
|
enum MultiplexStatus : std::uint8_t {
|
|
|
|
|
kNotApplicable = 0,
|
|
|
|
|
kMultiplexingDisabled = (1 << 0),
|
|
|
|
|
kMultiplexingEnabled = (1 << 1),
|
|
|
|
|
@ -40,12 +42,12 @@ enum MultiplexStatus {
|
|
|
|
|
kUserVariables = (1 << 3)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum ConnectionType {
|
|
|
|
|
enum ConnectionType : std::uint8_t {
|
|
|
|
|
kAdmin = 0,
|
|
|
|
|
kMySQL = 1
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class WarningCheckType {
|
|
|
|
|
enum class WarningCheckType : std::uint8_t {
|
|
|
|
|
kNotApplicable = 0,
|
|
|
|
|
kConnection = (1 << 0),
|
|
|
|
|
kCountQuery = (1 << 1),
|
|
|
|
|
@ -86,16 +88,16 @@ CommandLine cl;
|
|
|
|
|
std::array<std::map<size_t, MYSQL*>,2> conn_pool;
|
|
|
|
|
|
|
|
|
|
MYSQL* get_connection(const Connection& conn, bool enable_client_deprecate_eof) {
|
|
|
|
|
auto& my_conn = conn_pool[conn.conn_type];
|
|
|
|
|
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);
|
|
|
|
|
MYSQL* proxysql = mysql_init(nullptr);
|
|
|
|
|
if (!proxysql) {
|
|
|
|
|
fprintf(stderr, "File %s, line %d, Error: mysql_init failed\n", __FILE__, __LINE__);
|
|
|
|
|
return NULL;
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (enable_client_deprecate_eof) {
|
|
|
|
|
@ -105,17 +107,17 @@ MYSQL* get_connection(const Connection& conn, bool enable_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)) {
|
|
|
|
|
if (!mysql_real_connect(proxysql, cl.host, cl.admin_username, cl.admin_password, nullptr, cl.admin_port, nullptr, 0)) {
|
|
|
|
|
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql));
|
|
|
|
|
mysql_close(proxysql);
|
|
|
|
|
return NULL;
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
} 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)) {
|
|
|
|
|
if (!mysql_real_connect(proxysql, cl.host, cl.username, cl.password, nullptr, cl.port, nullptr, 0)) {
|
|
|
|
|
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql));
|
|
|
|
|
mysql_close(proxysql);
|
|
|
|
|
return NULL;
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
my_conn[conn.id] = proxysql;
|
|
|
|
|
@ -123,7 +125,9 @@ MYSQL* get_connection(const Connection& conn, bool enable_client_deprecate_eof)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void parse_result_json_column(MYSQL_RES* result, nlohmann::json& j) {
|
|
|
|
|
if (!result) return;
|
|
|
|
|
if (!result) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
while (MYSQL_ROW row = mysql_fetch_row(result)) {
|
|
|
|
|
j = nlohmann::json::parse(row[0]);
|
|
|
|
|
}
|
|
|
|
|
@ -165,12 +169,12 @@ int prepare_and_execute_stmt(MYSQL* mysql, const QueryInfo& query_info, MYSQL_ST
|
|
|
|
|
|
|
|
|
|
// get warning count from MySQL connection (MYSQL::warning_count)
|
|
|
|
|
int get_warnings_count_from_connection(MYSQL* mysql) {
|
|
|
|
|
return mysql_warning_count(mysql);
|
|
|
|
|
return static_cast<int>(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);
|
|
|
|
|
return static_cast<int>(mysql_stmt_warning_count(stmt));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// retrieve warning count through a query. This action does not clear the warning message list.
|
|
|
|
|
@ -183,7 +187,7 @@ int get_warnings_count(MYSQL* mysql) {
|
|
|
|
|
}
|
|
|
|
|
MYSQL_ROW row = mysql_fetch_row(mysql_result);
|
|
|
|
|
int warning_count = -1;
|
|
|
|
|
if (row != NULL && row[0] != NULL) {
|
|
|
|
|
if (row != nullptr && row[0] != nullptr) {
|
|
|
|
|
warning_count = atoi(row[0]);
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "File %s, line %d, Error: empty row from SHOW COUNT(*) WARNINGS\n",
|
|
|
|
|
@ -201,7 +205,7 @@ int get_warnings(MYSQL* mysql, std::list<std::tuple<LEVEL,CODE,MESSAGE>>& warnin
|
|
|
|
|
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
unsigned long fetched_row_count = 0;
|
|
|
|
|
int fetched_row_count = 0;
|
|
|
|
|
while (MYSQL_ROW row = mysql_fetch_row(mysql_result)) {
|
|
|
|
|
fetched_row_count++;
|
|
|
|
|
warning_list.emplace_back(std::make_tuple(std::string(row[0]),atoi(row[1]),std::string(row[2])));
|
|
|
|
|
@ -403,7 +407,7 @@ const std::vector<TestInfo> multiplexing_test = {
|
|
|
|
|
{ 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<int>(flag)) == static_cast<int>(flag))
|
|
|
|
|
#define IS_BIT_MASK_SET(variable,flag) (((variable) & static_cast<int>(flag)) == static_cast<int>(flag))
|
|
|
|
|
|
|
|
|
|
// base case
|
|
|
|
|
size_t check_count() { return 0; }
|
|
|
|
|
@ -415,14 +419,16 @@ size_t check_count(First&& first, Rest&&... rest) {
|
|
|
|
|
|
|
|
|
|
for (const auto& val : first) {
|
|
|
|
|
if (val.warning_check_info.type != WarningCheckType::kNotApplicable) {
|
|
|
|
|
if (val.warning_check_info.type == WarningCheckType::kAll)
|
|
|
|
|
if (val.warning_check_info.type == WarningCheckType::kAll) {
|
|
|
|
|
count += 3;
|
|
|
|
|
else
|
|
|
|
|
} else {
|
|
|
|
|
count += 1;
|
|
|
|
|
}
|
|
|
|
|
count += val.warning_check_info.warning_codes.size();
|
|
|
|
|
}
|
|
|
|
|
if (val.multiplex_status != 0)
|
|
|
|
|
if (val.multiplex_status != 0) {
|
|
|
|
|
count += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (count + check_count(rest...));
|
|
|
|
|
}
|
|
|
|
|
@ -445,11 +451,13 @@ void execute_tests(std::vector<std::pair<const char*, std::vector<TestInfo>>>& a
|
|
|
|
|
goto __exit;
|
|
|
|
|
}
|
|
|
|
|
if (test_info.query_info.prepare_stmt) {
|
|
|
|
|
if (prepare_and_execute_stmt(mysql, test_info.query_info, &stmt) == EXIT_FAILURE)
|
|
|
|
|
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)
|
|
|
|
|
if (execute_query(mysql, test_info.query_info) == EXIT_FAILURE) {
|
|
|
|
|
goto __exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int check_type = static_cast<int>(test_info.warning_check_info.type);
|
|
|
|
|
@ -488,14 +496,16 @@ void execute_tests(std::vector<std::pair<const char*, std::vector<TestInfo>>>& a
|
|
|
|
|
|
|
|
|
|
if (test_info.multiplex_status != MultiplexStatus::kNotApplicable) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
goto __exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stmt)
|
|
|
|
|
if (stmt) {
|
|
|
|
|
mysql_stmt_close(stmt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -529,19 +539,21 @@ int main(int argc, char** argv) {
|
|
|
|
|
diag(" - ProxySQL Host: %s", cl.host);
|
|
|
|
|
diag(" - Target User: %s", cl.username);
|
|
|
|
|
|
|
|
|
|
plan(check_count(TESTS_COMBINED)*2);
|
|
|
|
|
plan(static_cast<int>(check_count(TESTS_COMBINED)*2));
|
|
|
|
|
|
|
|
|
|
diag("Discovering target hostgroup for user %s...", cl.username);
|
|
|
|
|
int target_hg = 0;
|
|
|
|
|
MYSQL* admin_tmp = mysql_init(NULL);
|
|
|
|
|
if (admin_tmp != NULL) {
|
|
|
|
|
if (mysql_real_connect(admin_tmp, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
|
|
|
|
|
MYSQL* admin_tmp = mysql_init(nullptr);
|
|
|
|
|
if (admin_tmp != nullptr) {
|
|
|
|
|
if (mysql_real_connect(admin_tmp, cl.host, cl.admin_username, cl.admin_password, nullptr, cl.admin_port, nullptr, 0)) {
|
|
|
|
|
std::string hg_query = "SELECT default_hostgroup FROM mysql_users WHERE username='" + std::string(cl.username) + "' LIMIT 1";
|
|
|
|
|
if (mysql_query(admin_tmp, hg_query.c_str()) == 0) {
|
|
|
|
|
MYSQL_RES *res = mysql_store_result(admin_tmp);
|
|
|
|
|
if (res) {
|
|
|
|
|
MYSQL_ROW row = mysql_fetch_row(res);
|
|
|
|
|
if (row && row[0]) target_hg = atoi(row[0]);
|
|
|
|
|
if (row && row[0]) {
|
|
|
|
|
target_hg = atoi(row[0]);
|
|
|
|
|
}
|
|
|
|
|
mysql_free_result(res);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -553,9 +565,9 @@ int main(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
// Dump hostgroup state for debugging CI failures (hostgroup unreachable)
|
|
|
|
|
{
|
|
|
|
|
MYSQL* dbg_admin = mysql_init(NULL);
|
|
|
|
|
if (dbg_admin != NULL) {
|
|
|
|
|
if (mysql_real_connect(dbg_admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
|
|
|
|
|
MYSQL* dbg_admin = mysql_init(nullptr);
|
|
|
|
|
if (dbg_admin != nullptr) {
|
|
|
|
|
if (mysql_real_connect(dbg_admin, cl.host, cl.admin_username, cl.admin_password, nullptr, cl.admin_port, nullptr, 0)) {
|
|
|
|
|
dump_hostgroup_debug(dbg_admin, target_hg);
|
|
|
|
|
}
|
|
|
|
|
// Close the handle even if real_connect failed.
|
|
|
|
|
|