From 6cb522283dea756bdd86febca187889a7f4f4b06 Mon Sep 17 00:00:00 2001 From: Lisandro Pin Date: Wed, 8 Oct 2025 14:36:32 +0200 Subject: [PATCH] Implement a ignore_min_gtid_annotation global variable for ProxySQL When true, all `min_gtid` query annotations are ignored; see https://proxysql.com/documentation/query-annotations/ for details. This is useful on ProxySQL setups with multiple layers, where some layers mandate GTID-based routing while others don't. --- include/MySQL_Query_Processor.h | 24 ++++++++++++++++-------- include/MySQL_Thread.h | 2 ++ include/proxysql_structs.h | 2 ++ lib/MySQL_Session.cpp | 2 +- lib/MySQL_Thread.cpp | 25 +++++++++++++++---------- 5 files changed, 36 insertions(+), 19 deletions(-) diff --git a/include/MySQL_Query_Processor.h b/include/MySQL_Query_Processor.h index 5aaf471b0..ae9873300 100644 --- a/include/MySQL_Query_Processor.h +++ b/include/MySQL_Query_Processor.h @@ -6,7 +6,7 @@ #include "query_processor.h" class Command_Counter; -typedef struct _MySQL_Query_processor_Rule_t : public QP_rule_t { +typedef struct _MySQL_Query_processor_Rule_t : public QP_rule_t { int gtid_from_hostgroup; } MySQL_Query_Processor_Rule_t; @@ -75,14 +75,22 @@ private: inline void query_parser_first_comment_extended(const char* key, const char* value, MySQL_Query_Processor_Output* qpo) { if (!strcasecmp(key, "min_gtid")) { - size_t l = strlen(value); - if (_is_valid_gtid((char*)value, l)) { - char* buf = (char*)malloc(l + 1); - strncpy(buf, value, l); - buf[l + 1] = '\0'; - qpo->min_gtid = buf; + if (mysql_thread___ignore_min_gtid_annotations) { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Ignoring min_gtid=%s\n", value); } else { - proxy_warning("Invalid gtid value=%s\n", value); + size_t l = strlen(value); + if (_is_valid_gtid((char*)value, l)) { + char* buf = (char*)malloc(l + 1); + strncpy(buf, value, l); + buf[l] = '\0'; + + if (qpo->min_gtid) { + free(qpo->min_gtid); + } + qpo->min_gtid = buf; + } else { + proxy_warning("Invalid min_gtid value=%s\n", value); + } } } } diff --git a/include/MySQL_Thread.h b/include/MySQL_Thread.h index 296aebbe6..896324405 100644 --- a/include/MySQL_Thread.h +++ b/include/MySQL_Thread.h @@ -577,6 +577,8 @@ class MySQL_Threads_Handler #endif int show_processlist_extended; int processlist_max_query_length; + + bool ignore_min_gtid_annotations; } variables; struct { unsigned int mirror_sessions_current; diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h index c6bef82f2..893a2bfda 100644 --- a/include/proxysql_structs.h +++ b/include/proxysql_structs.h @@ -1303,6 +1303,7 @@ __thread int mysql_thread___client_host_cache_size; __thread int mysql_thread___client_host_error_counts; __thread int mysql_thread___handle_warnings; __thread int mysql_thread___evaluate_replication_lag_on_servers_load; +__thread bool mysql_thread___ignore_min_gtid_annotations; /* variables used for Query Cache */ __thread int mysql_thread___query_cache_size_MB; @@ -1605,6 +1606,7 @@ extern __thread int mysql_thread___client_host_cache_size; extern __thread int mysql_thread___client_host_error_counts; extern __thread int mysql_thread___handle_warnings; extern __thread int mysql_thread___evaluate_replication_lag_on_servers_load; +extern __thread bool mysql_thread___ignore_min_gtid_annotations; /* variables used for Query Cache */ extern __thread int mysql_thread___query_cache_size_MB; diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index 861279fa9..22b8f19dc 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -7162,7 +7162,7 @@ void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } void MySQL_Session::handler___client_DSS_QUERY_SENT___server_DSS_NOT_INITIALIZED__get_connection() { - // Get a MySQL Connection + // Get a MySQL Connection MySQL_Connection *mc=NULL; MySQL_Backend * _gtid_from_backend = NULL; diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index 5b2d467c9..3a2380e8a 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -510,6 +510,7 @@ static char * mysql_thread_variables_names[]= { (char *)"evaluate_replication_lag_on_servers_load", (char *)"proxy_protocol_networks", (char *)"protocol_compression_level", + (char *)"ignore_min_gtid_annotations", NULL }; @@ -1149,6 +1150,7 @@ MySQL_Threads_Handler::MySQL_Threads_Handler() { variables.log_mysql_warnings_enabled=false; variables.data_packets_history_size=0; variables.protocol_compression_level=3; + variables.ignore_min_gtid_annotations=false; // status variables status_variables.mirror_sessions_current=0; __global_MySQL_Thread_Variables_version=1; @@ -1373,6 +1375,7 @@ char * MySQL_Threads_Handler::get_variable_string(char *name) { if (!strcmp(name,"keep_multiplexing_variables")) return strdup(variables.keep_multiplexing_variables); if (!strcmp(name,"default_authentication_plugin")) return strdup(variables.default_authentication_plugin); if (!strcmp(name,"proxy_protocol_networks")) return strdup(variables.proxy_protocol_networks); + // LCOV_EXCL_START proxy_error("Not existing variable: %s\n", name); assert(0); return NULL; @@ -2171,6 +2174,7 @@ char ** MySQL_Threads_Handler::get_variables_list() { VariablesPointers_bool["stats_time_query_processor"] = make_tuple(&variables.stats_time_query_processor, false); VariablesPointers_bool["use_tcp_keepalive"] = make_tuple(&variables.use_tcp_keepalive, false); VariablesPointers_bool["verbose_query_error"] = make_tuple(&variables.verbose_query_error, false); + VariablesPointers_bool["ignore_min_gtid_annotations"] = make_tuple(&variables.ignore_min_gtid_annotations, false); #ifdef IDLE_THREADS VariablesPointers_bool["session_idle_show_processlist"] = make_tuple(&variables.session_idle_show_processlist, false); #endif // IDLE_THREADS @@ -2291,16 +2295,16 @@ char ** MySQL_Threads_Handler::get_variables_list() { VariablesPointers_int["eventslog_default_log"] = make_tuple(&variables.eventslog_default_log, 0, 1, false); VariablesPointers_int["eventslog_stmt_parameters"] = make_tuple(&variables.eventslog_stmt_parameters, 0, 1, false); // various - VariablesPointers_int["long_query_time"] = make_tuple(&variables.long_query_time, 0, 20*24*3600*1000, false); - VariablesPointers_int["max_allowed_packet"] = make_tuple(&variables.max_allowed_packet, 8192, 1024*1024*1024, false); - VariablesPointers_int["max_connections"] = make_tuple(&variables.max_connections, 1, 1000*1000, false); - VariablesPointers_int["max_stmts_per_connection"] = make_tuple(&variables.max_stmts_per_connection, 1, 1024, false); - VariablesPointers_int["max_stmts_cache"] = make_tuple(&variables.max_stmts_cache, 128, 1024*1024, false); - VariablesPointers_int["max_transaction_idle_time"] = make_tuple(&variables.max_transaction_idle_time, 1000, 20*24*3600*1000, false); - VariablesPointers_int["max_transaction_time"] = make_tuple(&variables.max_transaction_time, 1000, 20*24*3600*1000, false); - VariablesPointers_int["query_cache_size_mb"] = make_tuple(&variables.query_cache_size_MB, 0, 1024*10240, false); - VariablesPointers_int["query_cache_soft_ttl_pct"] = make_tuple(&variables.query_cache_soft_ttl_pct, 0, 100, false); - VariablesPointers_int["query_cache_handle_warnings"] = make_tuple(&variables.query_cache_handle_warnings, 0, 1, false); + VariablesPointers_int["long_query_time"] = make_tuple(&variables.long_query_time, 0, 20*24*3600*1000, false); + VariablesPointers_int["max_allowed_packet"] = make_tuple(&variables.max_allowed_packet, 8192, 1024*1024*1024, false); + VariablesPointers_int["max_connections"] = make_tuple(&variables.max_connections, 1, 1000*1000, false); + VariablesPointers_int["max_stmts_per_connection"] = make_tuple(&variables.max_stmts_per_connection, 1, 1024, false); + VariablesPointers_int["max_stmts_cache"] = make_tuple(&variables.max_stmts_cache, 128, 1024*1024, false); + VariablesPointers_int["max_transaction_idle_time"] = make_tuple(&variables.max_transaction_idle_time, 1000, 20*24*3600*1000, false); + VariablesPointers_int["max_transaction_time"] = make_tuple(&variables.max_transaction_time, 1000, 20*24*3600*1000, false); + VariablesPointers_int["query_cache_size_mb"] = make_tuple(&variables.query_cache_size_MB, 0, 1024*10240, false); + VariablesPointers_int["query_cache_soft_ttl_pct"] = make_tuple(&variables.query_cache_soft_ttl_pct, 0, 100, false); + VariablesPointers_int["query_cache_handle_warnings"] = make_tuple(&variables.query_cache_handle_warnings, 0, 1, false); #ifdef IDLE_THREADS VariablesPointers_int["session_idle_ms"] = make_tuple(&variables.session_idle_ms, 1, 3600*1000, false); @@ -4268,6 +4272,7 @@ void MySQL_Thread::refresh_variables() { REFRESH_VARIABLE_INT(client_host_error_counts); REFRESH_VARIABLE_INT(handle_warnings); REFRESH_VARIABLE_INT(evaluate_replication_lag_on_servers_load); + REFRESH_VARIABLE_BOOL(ignore_min_gtid_annotations); #ifdef DEBUG REFRESH_VARIABLE_BOOL(session_debug); #endif /* DEBUG */