From 8b526c69ed245b1ad13bdf0103983b2b090f486d Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Wed, 23 Oct 2024 13:12:11 +0500 Subject: [PATCH 1/4] Updated default value of cache_empty_result to -1, indicating that it has not been explicitly set --- include/query_processor.h | 2 +- ...xxxx_query_cache_stores_empty_result-t.cpp | 154 ++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 test/tap/tests/mysql-reg_test_xxxx_query_cache_stores_empty_result-t.cpp diff --git a/include/query_processor.h b/include/query_processor.h index 9d62330291..fd93abb719 100644 --- a/include/query_processor.h +++ b/include/query_processor.h @@ -164,7 +164,7 @@ class Query_Processor_Output { mirror_flagOUT=-1; next_query_flagIN=-1; cache_ttl=-1; - cache_empty_result=1; + cache_empty_result=-1; cache_timeout=-1; reconnect=-1; timeout=-1; diff --git a/test/tap/tests/mysql-reg_test_xxxx_query_cache_stores_empty_result-t.cpp b/test/tap/tests/mysql-reg_test_xxxx_query_cache_stores_empty_result-t.cpp new file mode 100644 index 0000000000..468502de1a --- /dev/null +++ b/test/tap/tests/mysql-reg_test_xxxx_query_cache_stores_empty_result-t.cpp @@ -0,0 +1,154 @@ + /** + * @file mysql-reg_test_4716_single_semicolon-t.cpp + * @brief This test aims to verify that ProxySQL handles a lone semicolon (;) input + * crashing. The expected behavior is for ProxySQL to either ignore the input or return an + * appropriate error message, rather than crashing or becoming unresponsive. + */ + +#include +#include + +#include "mysql.h" +#include "command_line.h" +#include "tap.h" +#include "utils.h" + +CommandLine cl; + +std::map getQueryCacheMetrics(MYSQL* proxy_admin) { + const char* query = "SELECT Variable_Name, Variable_Value FROM stats_mysql_global WHERE Variable_Name LIKE 'Query_Cache%';"; + diag("Running: %s", query); + + int query_res = mysql_query(proxy_admin, query); + if (query_res) { + BAIL_OUT("Query failed with error: %s", mysql_error(proxy_admin)); + return {}; + } + + std::map metrics{}; + MYSQL_RES* res = mysql_store_result(proxy_admin); + MYSQL_ROW row; + + while ((row = mysql_fetch_row(res))) { + metrics[row[0]] = atoi(row[1]); + } + + mysql_free_result(res); + return metrics; +} + +class TestMetrics { +public: + std::map before; + std::map after; + + void swap() { + before.swap(after); + } + + template + bool checkMetricDelta(const std::string& metric_name, int expected, BinaryOp op) { + if (before.find(metric_name) == before.end() || + after.find(metric_name) == after.end()) { + BAIL_OUT("Metric '%s' not found", metric_name.c_str()); + return false; + } + + int delta = after[metric_name] - before[metric_name]; + bool result = op(std::max(0, delta), expected); + + std::string bin_op_name = typeid(BinaryOp).name(); + bin_op_name = bin_op_name.substr(3, bin_op_name.size() - 6); + + ok(result, "Metric `%s` should be '%s' %d. Actual %d", metric_name.c_str(), bin_op_name.c_str(), expected, delta); + return result; + } +}; + + + +int main(int argc, char** argv) { + + plan(10); // Total number of tests planned + + if (cl.getEnv()) + return exit_status(); + + // Initialize Admin connection + 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; + } + + // Connnect to ProxySQL Admin + if (!mysql_real_connect(proxysql_admin, cl.host, /*cl.admin_username*/ "admin", /*cl.admin_password*/ "admin", NULL, /*cl.admin_port*/ 6032, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin)); + return -1; + } + + // Initialize Backend connection + MYSQL* proxysql_backend = mysql_init(NULL); + if (!proxysql_backend) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_backend)); + return -1; + } + + // Connect to Backend + if (!mysql_real_connect(proxysql_backend, cl.host, /*cl.username*/ "root", /*cl.password*/ "root", NULL, /*cl.port*/ 6033, NULL, 0)) { + fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_backend)); + return -1; + } + + MYSQL_QUERY(proxysql_admin, "DELETE FROM mysql_query_rules"); + MYSQL_QUERY(proxysql_admin, "INSERT INTO mysql_query_rules (rule_id,active,match_digest,cache_ttl) VALUES (2,1,'^SELECT',4000)"); + MYSQL_QUERY(proxysql_admin, "LOAD MYSQL QUERY RULES TO RUNTIME"); + MYSQL_QUERY(proxysql_admin, "UPDATE global_variables SET variable_value=0 WHERE variable_name='mysql-query_cache_stores_empty_result'"); + MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME"); + + TestMetrics metrics; + + metrics.before = getQueryCacheMetrics(proxysql_admin); + + if (mysql_query(proxysql_backend, "SELECT 1 WHERE 1!=1") == 0) { + MYSQL_RES* res = mysql_store_result(proxysql_backend); + ok(res != nullptr, "Query executed successfully. %s", mysql_error(proxysql_backend)); + mysql_free_result(res); + } + else { + ok(false, "Error executing query. %s", mysql_error(proxysql_admin)); + } + + metrics.after = getQueryCacheMetrics(proxysql_admin); + + metrics.checkMetricDelta<>("Query_Cache_Memory_bytes", 0, std::equal_to()); + metrics.checkMetricDelta<>("Query_Cache_count_SET", 0, std::equal_to()); + metrics.checkMetricDelta<>("Query_Cache_bytes_IN", 0, std::equal_to()); + metrics.checkMetricDelta<>("Query_Cache_Entries", 0, std::equal_to()); + + metrics.swap(); + + MYSQL_QUERY(proxysql_admin, "UPDATE global_variables SET variable_value=1 WHERE variable_name='mysql-query_cache_stores_empty_result'"); + MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME"); + + if (mysql_query(proxysql_backend, "SELECT 1 WHERE 1!=1") == 0) { + MYSQL_RES* res = mysql_store_result(proxysql_backend); + ok(res != nullptr, "Query executed successfully. %s", mysql_error(proxysql_backend)); + mysql_free_result(res); + } + else { + ok(false, "Error executing query. %s", mysql_error(proxysql_admin)); + } + + metrics.after = getQueryCacheMetrics(proxysql_admin); + + metrics.checkMetricDelta<>("Query_Cache_Memory_bytes", 1, std::greater()); + metrics.checkMetricDelta<>("Query_Cache_count_SET", 1, std::equal_to()); + metrics.checkMetricDelta<>("Query_Cache_bytes_IN", 1, std::greater()); + metrics.checkMetricDelta<>("Query_Cache_Entries", 1, std::equal_to()); + + mysql_close(proxysql_backend); + mysql_close(proxysql_admin); + + return exit_status(); +} From 65fba5d0a6f8eb8d4bfd6cf6eaf27629759fbc97 Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Wed, 23 Oct 2024 13:16:20 +0500 Subject: [PATCH 2/4] Added TAP test --- ...4723_query_cache_stores_empty_result-t.cpp | 168 ++++++++++++++++++ ...xxxx_query_cache_stores_empty_result-t.cpp | 154 ---------------- 2 files changed, 168 insertions(+), 154 deletions(-) create mode 100644 test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp delete mode 100644 test/tap/tests/mysql-reg_test_xxxx_query_cache_stores_empty_result-t.cpp diff --git a/test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp b/test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp new file mode 100644 index 0000000000..c40b1646b3 --- /dev/null +++ b/test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp @@ -0,0 +1,168 @@ +/** + * @file mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp + * @brief This test verfies that 'mysql-query_cache_stores_empty_result' variable works as expected. + * Specifically, it ensures that when this variable is set to `0`, empty results (zero rows) + * are not cached, and when set to `1`, they are cached. + * The test verifies this behavior by comparing the metrics before and after query execution. + */ + +#include +#include + +#include "mysql.h" +#include "command_line.h" +#include "tap.h" +#include "utils.h" + +CommandLine cl; + +std::map getQueryCacheMetrics(MYSQL* proxy_admin) { + const char* query = "SELECT Variable_Name, Variable_Value FROM stats_mysql_global WHERE Variable_Name LIKE 'Query_Cache%';"; + diag("Running: %s", query); + + int query_res = mysql_query(proxy_admin, query); + if (query_res) { + BAIL_OUT("Query failed with error: %s", mysql_error(proxy_admin)); + return {}; + } + + std::map metrics{}; + MYSQL_RES* res = mysql_store_result(proxy_admin); + if (!res) { + BAIL_OUT("Failed to store result: %s", mysql_error(proxy_admin)); + return {}; + } + + MYSQL_ROW row; + while ((row = mysql_fetch_row(res))) { + metrics[row[0]] = atoi(row[1]); + } + + mysql_free_result(res); + return metrics; +} + +class TestMetrics { +public: + std::map before; + std::map after; + + void swap() { + before.swap(after); + } + + template + bool checkMetricDelta(const std::string& metric_name, int expected, BinaryOp op) { + if (before.find(metric_name) == before.end() || after.find(metric_name) == after.end()) { + diag("Metric '%s' not found in either before or after map.", metric_name.c_str()); + return false; + } + + int delta = after[metric_name] - before[metric_name]; + bool result = op(std::max(0, delta), expected); + + diag("Checking metric '%s': Expected delta %d, Actual delta %d", metric_name.c_str(), expected, delta); + ok(result, "Metric `%s` delta is correct. Expected '%d', got '%d'", metric_name.c_str(), expected, delta); + return result; + } +}; + +// Helper function for executing MySQL queries with error handling +bool exec_query(MYSQL* conn, const char* query) { + diag("Running query: %s", query); + int query_res = mysql_query(conn, query); + if (query_res) { + diag("Query failed with error: %s", mysql_error(conn)); + return false; + } + return true; +} + +int main(int argc, char** argv) { + plan(10); // Total number of tests planned + + if (cl.getEnv()) + return exit_status(); + + // Initialize and connect to ProxySQL Admin + MYSQL* proxysql_admin = mysql_init(nullptr); + if (!proxysql_admin) { + BAIL_OUT("MySQL admin init failed."); + } + + if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_username, cl.admin_password, nullptr, cl.admin_port, nullptr, 0)) { + BAIL_OUT("Failed to connect to ProxySQL Admin: %s", mysql_error(proxysql_admin)); + } + + // Initialize and connect to ProxySQL Backend + MYSQL* proxysql_backend = mysql_init(nullptr); + if (!proxysql_backend) { + BAIL_OUT("MySQL backend init failed."); + } + + if (!mysql_real_connect(proxysql_backend, cl.host, cl.username, cl.password, nullptr, cl.port, nullptr, 0)) { + BAIL_OUT("Failed to connect to ProxySQL Backend: %s", mysql_error(proxysql_backend)); + } + + // Setting up test environment + MYSQL_QUERY(proxysql_admin, "DELETE FROM mysql_query_rules"); + MYSQL_QUERY(proxysql_admin, "INSERT INTO mysql_query_rules (rule_id,active,match_digest,cache_ttl) VALUES (2,1,'^SELECT',4000)"); + MYSQL_QUERY(proxysql_admin, "LOAD MYSQL QUERY RULES TO RUNTIME"); + + // Disable query cache storing empty result + MYSQL_QUERY(proxysql_admin, "UPDATE global_variables SET variable_value=0 WHERE variable_name='mysql-query_cache_stores_empty_result'"); + MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME"); + + TestMetrics metrics; + + metrics.before = getQueryCacheMetrics(proxysql_admin); + + // Execute the test query and check the result + if (exec_query(proxysql_backend, "SELECT 1 WHERE 1!=1")) { + MYSQL_RES* res = mysql_store_result(proxysql_backend); + ok(res != nullptr, "Query executed successfully."); + mysql_free_result(res); + } + else { + ok(false, "Error executing query."); + } + + // Fetch metrics after query execution + metrics.after = getQueryCacheMetrics(proxysql_admin); + + metrics.checkMetricDelta("Query_Cache_Memory_bytes", 0, std::equal_to()); + metrics.checkMetricDelta("Query_Cache_count_SET", 0, std::equal_to()); + metrics.checkMetricDelta("Query_Cache_bytes_IN", 0, std::equal_to()); + metrics.checkMetricDelta("Query_Cache_Entries", 0, std::equal_to()); + + // Swap the before and after metrics for the next phase + metrics.swap(); + + // Enable query cache storing empty result + MYSQL_QUERY(proxysql_admin, "UPDATE global_variables SET variable_value=1 WHERE variable_name='mysql-query_cache_stores_empty_result'"); + MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME"); + + // Execute the same query again and check the result + if (exec_query(proxysql_backend, "SELECT 1 WHERE 1!=1")) { + MYSQL_RES* res = mysql_store_result(proxysql_backend); + ok(res != nullptr, "Query executed successfully."); + mysql_free_result(res); + } + else { + ok(false, "Error executing query."); + } + + // Fetch metrics again and check for expected changes + metrics.after = getQueryCacheMetrics(proxysql_admin); + + metrics.checkMetricDelta("Query_Cache_Memory_bytes", 1, std::greater()); + metrics.checkMetricDelta("Query_Cache_count_SET", 1, std::equal_to()); + metrics.checkMetricDelta("Query_Cache_bytes_IN", 1, std::greater()); + metrics.checkMetricDelta("Query_Cache_Entries", 1, std::equal_to()); + + // Close the connections + mysql_close(proxysql_backend); + mysql_close(proxysql_admin); + + return exit_status(); +} diff --git a/test/tap/tests/mysql-reg_test_xxxx_query_cache_stores_empty_result-t.cpp b/test/tap/tests/mysql-reg_test_xxxx_query_cache_stores_empty_result-t.cpp deleted file mode 100644 index 468502de1a..0000000000 --- a/test/tap/tests/mysql-reg_test_xxxx_query_cache_stores_empty_result-t.cpp +++ /dev/null @@ -1,154 +0,0 @@ - /** - * @file mysql-reg_test_4716_single_semicolon-t.cpp - * @brief This test aims to verify that ProxySQL handles a lone semicolon (;) input - * crashing. The expected behavior is for ProxySQL to either ignore the input or return an - * appropriate error message, rather than crashing or becoming unresponsive. - */ - -#include -#include - -#include "mysql.h" -#include "command_line.h" -#include "tap.h" -#include "utils.h" - -CommandLine cl; - -std::map getQueryCacheMetrics(MYSQL* proxy_admin) { - const char* query = "SELECT Variable_Name, Variable_Value FROM stats_mysql_global WHERE Variable_Name LIKE 'Query_Cache%';"; - diag("Running: %s", query); - - int query_res = mysql_query(proxy_admin, query); - if (query_res) { - BAIL_OUT("Query failed with error: %s", mysql_error(proxy_admin)); - return {}; - } - - std::map metrics{}; - MYSQL_RES* res = mysql_store_result(proxy_admin); - MYSQL_ROW row; - - while ((row = mysql_fetch_row(res))) { - metrics[row[0]] = atoi(row[1]); - } - - mysql_free_result(res); - return metrics; -} - -class TestMetrics { -public: - std::map before; - std::map after; - - void swap() { - before.swap(after); - } - - template - bool checkMetricDelta(const std::string& metric_name, int expected, BinaryOp op) { - if (before.find(metric_name) == before.end() || - after.find(metric_name) == after.end()) { - BAIL_OUT("Metric '%s' not found", metric_name.c_str()); - return false; - } - - int delta = after[metric_name] - before[metric_name]; - bool result = op(std::max(0, delta), expected); - - std::string bin_op_name = typeid(BinaryOp).name(); - bin_op_name = bin_op_name.substr(3, bin_op_name.size() - 6); - - ok(result, "Metric `%s` should be '%s' %d. Actual %d", metric_name.c_str(), bin_op_name.c_str(), expected, delta); - return result; - } -}; - - - -int main(int argc, char** argv) { - - plan(10); // Total number of tests planned - - if (cl.getEnv()) - return exit_status(); - - // Initialize Admin connection - 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; - } - - // Connnect to ProxySQL Admin - if (!mysql_real_connect(proxysql_admin, cl.host, /*cl.admin_username*/ "admin", /*cl.admin_password*/ "admin", NULL, /*cl.admin_port*/ 6032, NULL, 0)) { - fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin)); - return -1; - } - - // Initialize Backend connection - MYSQL* proxysql_backend = mysql_init(NULL); - if (!proxysql_backend) { - fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_backend)); - return -1; - } - - // Connect to Backend - if (!mysql_real_connect(proxysql_backend, cl.host, /*cl.username*/ "root", /*cl.password*/ "root", NULL, /*cl.port*/ 6033, NULL, 0)) { - fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_backend)); - return -1; - } - - MYSQL_QUERY(proxysql_admin, "DELETE FROM mysql_query_rules"); - MYSQL_QUERY(proxysql_admin, "INSERT INTO mysql_query_rules (rule_id,active,match_digest,cache_ttl) VALUES (2,1,'^SELECT',4000)"); - MYSQL_QUERY(proxysql_admin, "LOAD MYSQL QUERY RULES TO RUNTIME"); - MYSQL_QUERY(proxysql_admin, "UPDATE global_variables SET variable_value=0 WHERE variable_name='mysql-query_cache_stores_empty_result'"); - MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME"); - - TestMetrics metrics; - - metrics.before = getQueryCacheMetrics(proxysql_admin); - - if (mysql_query(proxysql_backend, "SELECT 1 WHERE 1!=1") == 0) { - MYSQL_RES* res = mysql_store_result(proxysql_backend); - ok(res != nullptr, "Query executed successfully. %s", mysql_error(proxysql_backend)); - mysql_free_result(res); - } - else { - ok(false, "Error executing query. %s", mysql_error(proxysql_admin)); - } - - metrics.after = getQueryCacheMetrics(proxysql_admin); - - metrics.checkMetricDelta<>("Query_Cache_Memory_bytes", 0, std::equal_to()); - metrics.checkMetricDelta<>("Query_Cache_count_SET", 0, std::equal_to()); - metrics.checkMetricDelta<>("Query_Cache_bytes_IN", 0, std::equal_to()); - metrics.checkMetricDelta<>("Query_Cache_Entries", 0, std::equal_to()); - - metrics.swap(); - - MYSQL_QUERY(proxysql_admin, "UPDATE global_variables SET variable_value=1 WHERE variable_name='mysql-query_cache_stores_empty_result'"); - MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME"); - - if (mysql_query(proxysql_backend, "SELECT 1 WHERE 1!=1") == 0) { - MYSQL_RES* res = mysql_store_result(proxysql_backend); - ok(res != nullptr, "Query executed successfully. %s", mysql_error(proxysql_backend)); - mysql_free_result(res); - } - else { - ok(false, "Error executing query. %s", mysql_error(proxysql_admin)); - } - - metrics.after = getQueryCacheMetrics(proxysql_admin); - - metrics.checkMetricDelta<>("Query_Cache_Memory_bytes", 1, std::greater()); - metrics.checkMetricDelta<>("Query_Cache_count_SET", 1, std::equal_to()); - metrics.checkMetricDelta<>("Query_Cache_bytes_IN", 1, std::greater()); - metrics.checkMetricDelta<>("Query_Cache_Entries", 1, std::equal_to()); - - mysql_close(proxysql_backend); - mysql_close(proxysql_admin); - - return exit_status(); -} From 4d07b1702702269834382e20c766e237bff8886c Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Thu, 24 Oct 2024 11:57:25 +0500 Subject: [PATCH 3/4] Updated query --- .../mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp b/test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp index c40b1646b3..c6471e2530 100644 --- a/test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp +++ b/test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp @@ -118,7 +118,7 @@ int main(int argc, char** argv) { metrics.before = getQueryCacheMetrics(proxysql_admin); // Execute the test query and check the result - if (exec_query(proxysql_backend, "SELECT 1 WHERE 1!=1")) { + if (exec_query(proxysql_backend, "SELECT 1 FROM DUAL WHERE 1!=1")) { MYSQL_RES* res = mysql_store_result(proxysql_backend); ok(res != nullptr, "Query executed successfully."); mysql_free_result(res); @@ -143,7 +143,7 @@ int main(int argc, char** argv) { MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME"); // Execute the same query again and check the result - if (exec_query(proxysql_backend, "SELECT 1 WHERE 1!=1")) { + if (exec_query(proxysql_backend, "SELECT 1 FROM DUAL WHERE 1!=1")) { MYSQL_RES* res = mysql_store_result(proxysql_backend); ok(res != nullptr, "Query executed successfully."); mysql_free_result(res); From 67e45ecef29842f6ad8ff55bdfb7672be01a2f87 Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Tue, 29 Oct 2024 12:29:42 +0500 Subject: [PATCH 4/4] Fixed admin_host --- .../mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp b/test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp index c6471e2530..d36c5d53b0 100644 --- a/test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp +++ b/test/tap/tests/mysql-reg_test_4723_query_cache_stores_empty_result-t.cpp @@ -90,7 +90,7 @@ int main(int argc, char** argv) { BAIL_OUT("MySQL admin init failed."); } - if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_username, cl.admin_password, nullptr, cl.admin_port, nullptr, 0)) { + if (!mysql_real_connect(proxysql_admin, cl.admin_host, cl.admin_username, cl.admin_password, nullptr, cl.admin_port, nullptr, 0)) { BAIL_OUT("Failed to connect to ProxySQL Admin: %s", mysql_error(proxysql_admin)); }