mirror of https://github.com/sysown/proxysql
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
6.0 KiB
158 lines
6.0 KiB
#include <cstdlib>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <unistd.h>
|
|
|
|
#include <string>
|
|
#include <sstream>
|
|
#include "mysql.h"
|
|
|
|
#include "tap.h"
|
|
#include "command_line.h"
|
|
#include "utils.h"
|
|
|
|
struct transaction_param {
|
|
struct next_transaction {
|
|
std::string set_transaction_val;
|
|
std::string exp_transaction_val;
|
|
};
|
|
|
|
std::string session_transaction_val;
|
|
std::vector<next_transaction> next_transaction_val;
|
|
};
|
|
|
|
transaction_param next_trx_isolation_level_test[] = {
|
|
{"REPEATABLE READ", {{"", "REPEATABLE READ"}, {"SERIALIZABLE", "SERIALIZABLE"}, {"", "REPEATABLE READ"}}},
|
|
{"REPEATABLE READ", {{"", "REPEATABLE READ"}, {"READ UNCOMMITTED", "READ UNCOMMITTED"}, {"", "REPEATABLE READ"}}},
|
|
{"REPEATABLE READ", {{"", "REPEATABLE READ"}, {"READ COMMITTED", "READ COMMITTED"}, {"", "REPEATABLE READ"}}},
|
|
{"SERIALIZABLE", {{"", "SERIALIZABLE"}, {"REPEATABLE READ", "REPEATABLE READ"}, {"", "SERIALIZABLE"}}},
|
|
};
|
|
|
|
transaction_param next_trx_access_mode_test[] = {
|
|
{"READ WRITE", {{"", "READ WRITE"}, {"READ ONLY", "READ ONLY"}, {"", "READ WRITE"}}},
|
|
{"READ WRITE", {{"", "READ WRITE"}, {"READ WRITE", "READ WRITE"}, {"", "READ WRITE"}}},
|
|
{"READ ONLY", {{"", "READ ONLY"}, {"READ ONLY", "READ ONLY"}, {"", "READ ONLY"}}},
|
|
{"READ ONLY", {{"", "READ ONLY"}, {"READ WRITE", "READ WRITE"}, {"", "READ ONLY"}}},
|
|
};
|
|
|
|
int check_transaction_isolation_level(MYSQL* mysql) {
|
|
const std::string set_session_trx_isolation_level = "SET SESSION TRANSACTION ISOLATION LEVEL ";
|
|
const std::string set_next_trx_isolation_level = "SET TRANSACTION ISOLATION LEVEL ";
|
|
const std::string get_trx_isolation_level = "SELECT trx_isolation_level FROM information_schema.INNODB_TRX trx WHERE trx_mysql_thread_id=CONNECTION_ID();";
|
|
const unsigned int test_size = sizeof(next_trx_isolation_level_test) / sizeof(transaction_param);
|
|
|
|
for (unsigned int i = 0; i < test_size; i++) {
|
|
const transaction_param& param = next_trx_isolation_level_test[i];
|
|
|
|
if (param.session_transaction_val.empty() == false) {
|
|
MYSQL_QUERY(mysql, (set_session_trx_isolation_level + param.session_transaction_val).c_str());
|
|
}
|
|
|
|
for (const auto& isolation_level : param.next_transaction_val) {
|
|
if (isolation_level.set_transaction_val.empty() == false) {
|
|
MYSQL_QUERY(mysql, (set_next_trx_isolation_level + isolation_level.set_transaction_val).c_str());
|
|
}
|
|
|
|
MYSQL_QUERY(mysql, "BEGIN");
|
|
MYSQL_QUERY(mysql, "INSERT INTO sbtest1 (id) VALUES (NULL)");
|
|
MYSQL_QUERY(mysql, get_trx_isolation_level.c_str());
|
|
|
|
MYSQL_RES *res = mysql_store_result(mysql);
|
|
MYSQL_ROW row;
|
|
|
|
const unsigned long long num_rows = mysql_num_rows(res);
|
|
ok(num_rows == 1, "check_transaction_isolation_level() -> mysql_num_rows(), expected: 1, actual: %llu", num_rows);
|
|
while ((row = mysql_fetch_row(res))) {
|
|
ok(strncmp(isolation_level.exp_transaction_val.c_str(), row[0], isolation_level.exp_transaction_val.size()) == 0, "check_transaction_isolation_level() -> row: expected: \"%s\", actual: \"%s\"", isolation_level.exp_transaction_val.c_str(), row[0]);
|
|
}
|
|
mysql_free_result(res);
|
|
MYSQL_QUERY(mysql, "ROLLBACK");
|
|
sleep(1);
|
|
}
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int check_transaction_access_mode(MYSQL* mysql) {
|
|
const char* access_mode_mapping[] = { "READ WRITE", "READ ONLY" };
|
|
const std::string set_session_trx_access_mode = "SET SESSION TRANSACTION ";
|
|
const std::string set_next_trx_access_mode = "SET TRANSACTION ";
|
|
const std::string get_trx_access_mode = "SELECT trx_is_read_only FROM information_schema.INNODB_TRX trx WHERE trx_mysql_thread_id=CONNECTION_ID();";
|
|
const unsigned int test_size = sizeof(next_trx_access_mode_test) / sizeof(transaction_param);
|
|
|
|
for (unsigned int i = 0; i < test_size ; i++) {
|
|
const transaction_param& param = next_trx_access_mode_test[i];
|
|
|
|
if (param.session_transaction_val.empty() == false) {
|
|
MYSQL_QUERY(mysql, (set_session_trx_access_mode + param.session_transaction_val).c_str());
|
|
}
|
|
|
|
for (const auto& access_mode : param.next_transaction_val) {
|
|
if (access_mode.set_transaction_val.empty() == false) {
|
|
MYSQL_QUERY(mysql, (set_next_trx_access_mode + access_mode.set_transaction_val).c_str());
|
|
}
|
|
|
|
MYSQL_QUERY(mysql, "BEGIN");
|
|
MYSQL_QUERY(mysql, "SELECT COUNT(*) FROM sbtest1");
|
|
mysql_free_result(mysql_store_result(mysql));
|
|
|
|
MYSQL_QUERY(mysql, get_trx_access_mode.c_str());
|
|
|
|
MYSQL_RES *res = mysql_store_result(mysql);
|
|
MYSQL_ROW row;
|
|
|
|
const unsigned long long num_rows = mysql_num_rows(res);
|
|
ok(num_rows == 1, "check_transaction_access_mode() -> mysql_num_rows(), expected: 1, actual: %llu", num_rows);
|
|
while ((row = mysql_fetch_row(res))) {
|
|
const char* access_mode_str = access_mode_mapping[atoi(row[0])];
|
|
ok(strncmp(access_mode.exp_transaction_val.c_str(), access_mode_str, access_mode.exp_transaction_val.size()) == 0, "check_transaction_access_mode() -> row: expected: \"%s\", actual: \"%s\"", access_mode.exp_transaction_val.c_str(), access_mode_str);
|
|
}
|
|
mysql_free_result(res);
|
|
MYSQL_QUERY(mysql, "ROLLBACK");
|
|
sleep(1);
|
|
}
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
CommandLine cl;
|
|
|
|
if(cl.getEnv())
|
|
return exit_status();
|
|
|
|
plan(48);
|
|
|
|
MYSQL* mysql = mysql_init(NULL);
|
|
if (!mysql)
|
|
return exit_status();
|
|
|
|
// if (!mysql_real_connect(mysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
|
|
if (!mysql_real_connect(mysql, cl.root_host, cl.root_username, cl.root_password, NULL, cl.root_port, NULL, 0)) {
|
|
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(mysql));
|
|
return exit_status();
|
|
}
|
|
|
|
if (create_table_test_sbtest1(0,mysql)) {
|
|
fprintf(stderr, "File %s, line %d, Error: create_table_test_sbtest1() failed\n", __FILE__, __LINE__);
|
|
return exit_status();
|
|
}
|
|
|
|
diag("Waiting few seconds for replication...");
|
|
sleep(2);
|
|
MYSQL_QUERY(mysql, "USE test");
|
|
|
|
if (check_transaction_isolation_level(mysql)) {
|
|
fprintf(stderr, "check_transaction_isolation_level() failed\n");
|
|
return exit_status();
|
|
}
|
|
if (check_transaction_access_mode(mysql)) {
|
|
fprintf(stderr, "check_transaction_access_mode() failed\n");
|
|
return exit_status();
|
|
}
|
|
|
|
mysql_close(mysql);
|
|
return exit_status();
|
|
}
|