Merge pull request #3368 from sysown/v2.1.1-2543

Closes #2543: Admin and C# driver
pull/3373/head
René Cannaò 5 years ago committed by GitHub
commit b8ab99ba52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3444,6 +3444,58 @@ SQLite3_result * ProxySQL_Admin::generate_show_table_status(const char *tablenam
return result;
}
/**
* @brief Helper function to format the received hours into a string
* in the format ('HH'|'0H'|'-0H'|'-HH'). Depending on the supplied
* number digit count and sign.
* @param num A number to be converted to described format.
* @return std::string holding the converted number.
*/
const std::string format_timezone_hours(const int num) {
std::string result {};
const std::string base_num = std::to_string(num);
if (num < 10 && num >= 0) {
result = "0" + base_num;
} else if (num > -10 && num < 0) {
result = base_num.substr(0, 1) + "0" + base_num.substr(1);
} else if (num <= -10) {
result = base_num;
}
return result;
}
/**
* @brief Helper function that converts the current timezone
* expressed in seconds into a string of the format:
* - 'hours' + ':00:00'.
* Following the same pattern as the possible values returned by the SQL query
* 'SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP())' in a MySQL server.
* @return A string holding the specified representation of the
* supplied timezone.
*/
std::string timediff_timezone_offset() {
// explecitly call 'tzset' to make sure '::timezone' is set
tzset();
// get the global variable
long int timezone = ::timezone;
// first negate the received number
timezone = -timezone;
// transform into hours
int timezone_offset_hours = timezone / 3600;
// create an string with the resulting 'hours' + ':00:00'
std::string time_zone_offset {
format_timezone_hours(timezone_offset_hours) + ":00:00"
};
return time_zone_offset;
}
void admin_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt) {
@ -4050,6 +4102,46 @@ void admin_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt) {
goto __run_query;
}
// implementation for 'SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP())' in order to support'csharp' connector. See #2543
if (!strncasecmp("SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP())", query_no_space, strlen("SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP())"))) {
l_free(query_length,query);
char *query1=(char*)"SELECT '%s' as 'TIMEDIFF(NOW(), UTC_TIMESTAMP()'";
// compute the timezone diff
std::string timezone_offset_str = timediff_timezone_offset();
char *query2=(char *)malloc(strlen(query1) + strlen(timezone_offset_str.c_str()) + 1);
// format the query
sprintf(query2, query1, timezone_offset_str.c_str());
// copy the resulting query
query=l_strdup(query2);
query_length=strlen(query2) + 1;
// free the buffer used to format
free(query2);
goto __run_query;
}
// implementation for '"select @@max_allowed_packet, @@character_set_client, @@character_set_connection, @@license, @@sql_mode, @@lower_case_table_names"'
// in order to support 'csharp' connector. See #2543
if (
!strncasecmp(
"select @@max_allowed_packet, @@character_set_client, @@character_set_connection, @@license, @@sql_mode, @@lower_case_table_names",
query_no_space,
strlen("select @@max_allowed_packet, @@character_set_client, @@character_set_connection, @@license, @@sql_mode, @@lower_case_table_names")
)
) {
l_free(query_length,query);
char *query1=
const_cast<char*>(
"select '67108864' as '@@max_allowed_packet', 'utf8' as '@@character_set_client', 'utf8' as '@@character_set_connection', '' as '@@license', '' as '@@sql_mode', '' as '@@lower_case_table_names'"
);
query=l_strdup(query1);
query_length=strlen(query1)+1;
goto __run_query;
}
if (query_no_space_length==SELECT_DB_USER_LEN) {
if (!strncasecmp(SELECT_DB_USER, query_no_space, query_no_space_length)) {
l_free(query_length,query);

@ -0,0 +1,117 @@
/**
* @file test_csharp_connector_support-t.cpp
* @brief This test verifies the new added queries for supporting C# connector for the 'Admin module'.
*/
#include <vector>
#include <string>
#include <stdio.h>
#include <mysql.h>
#include "tap.h"
#include "command_line.h"
#include "utils.h"
int main(int argc, char** argv) {
CommandLine cl;
if (cl.getEnv()) {
diag("Failed to get the required environmental variables.");
return -1;
}
plan(4);
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;
}
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 -1;
}
// Test the new introduced query "SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP())"
int query_res = mysql_query(proxysql_admin, "SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP())");
ok(
query_res == 0,
"Query \"SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP())\" should succeed."
);
if (query_res == 0) {
MYSQL_RES* select_res = mysql_store_result(proxysql_admin);
unsigned int num_fields = mysql_num_fields(select_res);
MYSQL_ROW select_row = mysql_fetch_row(select_res);
if (select_row && num_fields == 1) {
std::string select_row_str { select_row[0] };
bool exp_concat_res = true;
ok(exp_concat_res, "Output received for \"SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP())\" was: %s", select_row_str.c_str());
}
mysql_free_result(select_res);
} else {
ok(false, "Query result for \"SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP())\" should be 0. Was: %d", query_res);
}
MYSQL_RES* select_res = NULL;
int max_allowed_packet = 0;
std::string character_set_client {};
std::string character_set_connection {};
std::string license {};
std::string sql_mode {};
std::string lower_case_table_names {};
// Test the new introduced query "SELECT @@max_allowed_packet, @@character_set_client, @@character_set_connection, @@license, @@sql_mode, @@lower_case_table_names"
query_res = mysql_query(proxysql_admin, "SELECT @@max_allowed_packet, @@character_set_client, @@character_set_connection, @@license, @@sql_mode, @@lower_case_table_names");
ok(
query_res == 0,
"Query \"SELECT @@max_allowed_packet, @@character_set_client, @@character_set_connection, @@license, @@sql_mode, @@lower_case_table_names\" should succeed."
);
if (query_res == 0) {
select_res = mysql_store_result(proxysql_admin);
unsigned int select_num_fields = mysql_num_fields(select_res);
if (select_res && select_num_fields == 6) {
MYSQL_ROW select_row = mysql_fetch_row(select_res);
max_allowed_packet = atoi(select_row[0]);
character_set_client = select_row[1];
character_set_connection = select_row[2];
license = select_row[3];
sql_mode = select_row[4];
lower_case_table_names = select_row[5];
bool expected_values =
max_allowed_packet == 67108864 &&
character_set_client == "utf8" &&
character_set_connection == "utf8" &&
license == "" &&
sql_mode == "" &&
lower_case_table_names == "";
ok(
expected_values,
"Query result for \"SELECT @@max_allowed_packet, @@character_set_client, @@character_set_connection, @@license, @@sql_mode, @@lower_case_table_names\" should match the expected hardcoded values:\n"
" (expected=(@@max_allowed_packet:67108864, @@character_set_client:'utf8', @@character_set_connection='utf8', @@license='', @@sql_mode='', @@lower_case_table_names=''),\n"
" (actual=(@@max_allowed_packet:%d, @@character_set_client:'%s', @@character_set_connection='%s', @@license='%s', @@sql_mode='%s', @@lower_case_table_names='%s')))",
max_allowed_packet,
character_set_client.c_str(),
character_set_connection.c_str(),
license.c_str(),
sql_mode.c_str(),
lower_case_table_names.c_str()
);
} else {
ok(false, "Invalid resulset. Expected 'num_fields' = 6, not %d", select_num_fields);
}
}
mysql_free_result(select_res);
return exit_status();
}
Loading…
Cancel
Save