diff --git a/deps/mariadb-client-library/client_deprecate_eof.patch b/deps/mariadb-client-library/client_deprecate_eof.patch index a926e55a4..bf89e8e38 100644 --- a/deps/mariadb-client-library/client_deprecate_eof.patch +++ b/deps/mariadb-client-library/client_deprecate_eof.patch @@ -12,7 +12,7 @@ index 62cf71c..c05e9a3 100644 COM_MULTI_OFF= 0, COM_MULTI_CANCEL, diff --git include/mariadb_com.h include/mariadb_com.h -index 7e722a0..3d89fdf 100644 +index 7e722a0..dc121c7 100644 --- include/mariadb_com.h +++ include/mariadb_com.h @@ -160,6 +160,7 @@ enum enum_server_command @@ -23,22 +23,21 @@ index 7e722a0..3d89fdf 100644 #define CLIENT_PROGRESS (1UL << 29) /* client supports progress indicator */ #define CLIENT_PROGRESS_OBSOLETE CLIENT_PROGRESS #define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) -@@ -204,6 +205,7 @@ enum enum_server_command +@@ -204,8 +205,14 @@ enum enum_server_command CLIENT_REMEMBER_OPTIONS |\ CLIENT_PLUGIN_AUTH |\ CLIENT_SESSION_TRACKING |\ + CLIENT_DEPRECATE_EOF |\ CLIENT_CONNECT_ATTRS) ++/* Client capabilities *does no* longer holds 'CLIENT_DEPRECATE_EOF' flag ++ * by default. This is part of ProxySQL feature for conditionally disabling ++ * 'deprecate_eof' support in both client and backend connections. For more ++ * context see #3280. ++ */ #define CLIENT_CAPABILITIES (CLIENT_MYSQL | \ -@@ -215,6 +217,7 @@ enum enum_server_command - CLIENT_PROTOCOL_41 |\ - CLIENT_PLUGIN_AUTH |\ - CLIENT_SESSION_TRACKING |\ -+ CLIENT_DEPRECATE_EOF |\ - CLIENT_CONNECT_ATTRS) - - #define CLIENT_DEFAULT_FLAGS ((CLIENT_SUPPORTED_FLAGS & ~CLIENT_COMPRESS)\ + CLIENT_LONG_FLAG |\ + CLIENT_TRANSACTIONS |\ diff --git include/mariadb_stmt.h include/mariadb_stmt.h index d07540e..4930573 100644 --- include/mariadb_stmt.h @@ -66,7 +65,7 @@ index 15be4fc..a69e637 100644 See bug conc-57 */ diff --git libmariadb/mariadb_lib.c libmariadb/mariadb_lib.c -index 8c2a99b..249e981 100644 +index 8c2a99b..e849b76 100644 --- libmariadb/mariadb_lib.c +++ libmariadb/mariadb_lib.c @@ -144,6 +144,7 @@ struct st_mariadb_methods MARIADB_DEFAULT_METHODS; @@ -490,7 +489,24 @@ index 8c2a99b..249e981 100644 { if (mysql->net.last_errno == CR_SERVER_LOST) my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, -@@ -2290,14 +2446,13 @@ int mthd_my_read_query_result(MYSQL *mysql) +@@ -1593,6 +1749,16 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, + } + } + ++ /* If client flags doesn't have 'deprecate_eof' we forcely disable the server capability, ++ * This, in combination with the capability flag 'CLIENT_DEPRECATE_EOF' being disabled by default, ++ * completely disables the library support for CLIENT_DEPRECATE_EOF. This two changes were introduced ++ * as part of ProxySQL capability for controlling 'deprecate_eof' support in both client and ++ * backend connections. For more context see: #3280. ++ */ ++ if ((mysql->options.client_flag & CLIENT_DEPRECATE_EOF) == 0) { ++ mysql->server_capabilities &= ~CLIENT_DEPRECATE_EOF; ++ } ++ + /* pad 2 */ + end+= 18; + +@@ -2290,14 +2456,13 @@ int mthd_my_read_query_result(MYSQL *mysql) { uchar *pos; ulong field_count; @@ -506,7 +522,7 @@ index 8c2a99b..249e981 100644 { return(1); } -@@ -2310,7 +2465,7 @@ get_info: +@@ -2310,7 +2475,7 @@ get_info: { int error=mysql_handle_local_infile(mysql, (char *)pos, can_local_infile); @@ -515,7 +531,7 @@ index 8c2a99b..249e981 100644 return(-1); goto get_info; /* Get info packet */ } -@@ -2318,12 +2473,13 @@ get_info: +@@ -2318,12 +2483,13 @@ get_info: mysql->server_status|= SERVER_STATUS_IN_TRANS; mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */ @@ -535,7 +551,7 @@ index 8c2a99b..249e981 100644 mysql->status=MYSQL_STATUS_GET_RESULT; mysql->field_count=field_count; return(0); -@@ -2704,21 +2860,17 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild) +@@ -2704,21 +2870,17 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild) MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql) { @@ -560,7 +576,7 @@ index 8c2a99b..249e981 100644 mysql->status=MYSQL_STATUS_GET_RESULT; mysql->field_count=field_count; return(mysql_store_result(mysql)); -@@ -4164,7 +4316,7 @@ mysql_debug(const char *debug __attribute__((unused))) +@@ -4164,7 +4326,7 @@ mysql_debug(const char *debug __attribute__((unused))) *********************************************************************/ ulong STDCALL mysql_net_read_packet(MYSQL *mysql) { diff --git a/include/MySQL_Thread.h b/include/MySQL_Thread.h index a3a5dc5a4..5295300aa 100644 --- a/include/MySQL_Thread.h +++ b/include/MySQL_Thread.h @@ -513,6 +513,8 @@ class MySQL_Threads_Handler bool query_cache_stores_empty_result; bool kill_backend_connection_when_disconnect; bool client_session_track_gtid; + bool enable_client_deprecate_eof; + bool enable_server_deprecate_eof; } variables; struct { unsigned int mirror_sessions_current; diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h index 0523a04dd..c51351bc2 100644 --- a/include/proxysql_structs.h +++ b/include/proxysql_structs.h @@ -765,6 +765,8 @@ __thread bool mysql_thread___kill_backend_connection_when_disconnect; __thread bool mysql_thread___client_session_track_gtid; __thread char * mysql_thread___default_variables[SQL_NAME_LAST]; __thread int mysql_thread___query_digests_grouping_limit; +__thread bool mysql_thread___enable_client_deprecate_eof; +__thread bool mysql_thread___enable_server_deprecate_eof; /* variables used for Query Cache */ __thread int mysql_thread___query_cache_size_MB; @@ -914,6 +916,8 @@ extern __thread bool mysql_thread___kill_backend_connection_when_disconnect; extern __thread bool mysql_thread___client_session_track_gtid; extern __thread char * mysql_thread___default_variables[SQL_NAME_LAST]; extern __thread int mysql_thread___query_digests_grouping_limit; +extern __thread bool mysql_thread___enable_client_deprecate_eof; +extern __thread bool mysql_thread___enable_server_deprecate_eof; /* variables used for Query Cache */ extern __thread int mysql_thread___query_cache_size_MB; diff --git a/lib/MySQL_Protocol.cpp b/lib/MySQL_Protocol.cpp index 3f9ebf681..03908e4a7 100644 --- a/lib/MySQL_Protocol.cpp +++ b/lib/MySQL_Protocol.cpp @@ -1373,7 +1373,12 @@ bool MySQL_Protocol::generate_pkt_initial_handshake(bool send, void **ptr, unsig uint8_t uint8_charset = ci->nr & 255; memcpy(_ptr+l,&uint8_charset, sizeof(uint8_charset)); l+=sizeof(uint8_charset); memcpy(_ptr+l,&server_status, sizeof(server_status)); l+=sizeof(server_status); - if (deprecate_eof_active) { + // we conditionally reply the client specifying in 'server_capabilities' that + // 'CLIENT_DEPRECATE_EOF' is available if explicitly enabled by 'mysql-enable_client_deprecate_eof' + // variable. This is the first step of ensuring that client connections doesn't + // enable 'CLIENT_DEPRECATE_EOF' unless explicitly stated by 'mysql-enable_client_deprecate_eof'. + // Second step occurs during client handshake response (process_pkt_handshake_response). + if (deprecate_eof_active && mysql_thread___enable_client_deprecate_eof) { memcpy(_ptr+l,"\x8f\x81\x15",3); l+=3; } else { @@ -1714,6 +1719,18 @@ bool MySQL_Protocol::process_pkt_handshake_response(unsigned char *pkt, unsigned if (capabilities & CLIENT_MULTI_STATEMENTS) { capabilities |= CLIENT_MULTI_RESULTS; } + // we enforce disabling 'CLIENT_DEPRECATE_EOF' from the supported capabilities + // in case it's explicitly disabled by global variable 'mysql_thread___enable_client_deprecate_eof'. + // This is because further checks to actually threat the connection as a connection + // supporting 'CLIENT_DEPRECATE_EOF' rely in 'client_flag' field from + // 'MySQL_Connection::options'. + // This is the second step for ensuring that the connection is being handling + // in both ProxySQL and client side as a connection without 'CLIENT_DEPRECATE_EOF' support. + // First step is replying to client during initial handshake (in 'generate_pkt_initial_handshake') + // specifying no 'CLIENT_DEPRECATE_EOF' support in 'server_capabilities'. + if (!mysql_thread___enable_client_deprecate_eof) { + capabilities &= ~CLIENT_DEPRECATE_EOF; + } (*myds)->myconn->options.client_flag = capabilities; pkt += sizeof(uint32_t); max_pkt = CPY4(pkt); diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index e90fe322c..30337f953 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -990,6 +990,7 @@ void MySQL_Session::generate_proxysql_internal_session_json(json &j) { j["conn"]["client_flag"]["client_found_rows"] = (client_myds->myconn->options.client_flag & CLIENT_FOUND_ROWS ? 1 : 0); j["conn"]["client_flag"]["client_multi_statements"] = (client_myds->myconn->options.client_flag & CLIENT_MULTI_STATEMENTS ? 1 : 0); j["conn"]["client_flag"]["client_multi_results"] = (client_myds->myconn->options.client_flag & CLIENT_MULTI_RESULTS ? 1 : 0); + j["conn"]["client_flag"]["client_deprecate_eof"] = (client_myds->myconn->options.client_flag & CLIENT_DEPRECATE_EOF ? 1 : 0); j["conn"]["no_backslash_escapes"] = client_myds->myconn->options.no_backslash_escapes; j["conn"]["status"]["compression"] = client_myds->myconn->get_status(STATUS_MYSQL_CONNECTION_COMPRESSION); j["conn"]["status"]["transaction"] = client_myds->myconn->get_status(STATUS_MYSQL_CONNECTION_TRANSACTION); @@ -1049,6 +1050,7 @@ void MySQL_Session::generate_proxysql_internal_session_json(json &j) { j["backends"][i]["conn"]["client_flag"]["value"] = _myconn->options.client_flag; j["backends"][i]["conn"]["client_flag"]["client_found_rows"] = (_myconn->options.client_flag & CLIENT_FOUND_ROWS ? 1 : 0); j["backends"][i]["conn"]["client_flag"]["client_multi_statements"] = (_myconn->options.client_flag & CLIENT_MULTI_STATEMENTS ? 1 : 0); + j["backends"][i]["conn"]["client_flag"]["client_deprecate_eof"] = (_myconn->options.client_flag & CLIENT_DEPRECATE_EOF ? 1 : 0); if (_myconn->mysql && _myconn->ret_mysql) { MYSQL * _my = _myconn->mysql; sprintf(buff,"%p",_my); diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index 187cdf020..744cff02c 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -420,6 +420,8 @@ static char * mysql_thread_variables_names[]= { (char *)"connect_timeout_client", (char *)"connect_timeout_server", (char *)"connect_timeout_server_max", + (char *)"enable_client_deprecate_eof", + (char *)"enable_server_deprecate_eof", (char *)"eventslog_filename", (char *)"eventslog_filesize", (char *)"eventslog_default_log", @@ -1156,6 +1158,8 @@ MySQL_Threads_Handler::MySQL_Threads_Handler() { variables.session_debug=true; #endif /*debug */ variables.query_digests_grouping_limit = 3; + variables.enable_client_deprecate_eof=true; + variables.enable_server_deprecate_eof=true; // status variables status_variables.mirror_sessions_current=0; __global_MySQL_Thread_Variables_version=1; @@ -1461,6 +1465,8 @@ int MySQL_Threads_Handler::get_variable_int(const char *name) { if (!strcmp(name,"eventslog_default_log")) return (int)variables.eventslog_default_log; if (!strcmp(name,"eventslog_filesize")) return (int)variables.eventslog_filesize; if (!strcmp(name,"eventslog_format")) return (int)variables.eventslog_format; + if (!strcmp(name,"enable_client_deprecate_eof")) return (int)variables.enable_client_deprecate_eof; + if (!strcmp(name,"enable_server_deprecate_eof")) return (int)variables.enable_server_deprecate_eof; break; case 'f': if (!strcmp(name,"forward_autocommit")) return (int)variables.forward_autocommit; @@ -1890,7 +1896,12 @@ char * MySQL_Threads_Handler::get_variable(char *name) { // this is the public f sprintf(intbuf,"%d",variables.automatic_detect_sqli); return strdup(intbuf); } - + if (!strcasecmp(name,"enable_client_deprecate_eof")) { + return strdup((variables.enable_client_deprecate_eof ? "true" : "false")); + } + if (!strcasecmp(name,"enable_server_deprecate_eof")) { + return strdup((variables.enable_server_deprecate_eof ? "true" : "false")); + } if (!strcasecmp(name,"throttle_connections_per_sec_to_hostgroup")) { sprintf(intbuf,"%d",variables.throttle_connections_per_sec_to_hostgroup); return strdup(intbuf); @@ -3035,7 +3046,28 @@ bool MySQL_Threads_Handler::set_variable(char *name, const char *value) { // thi } return false; // we couldn't set it to a valid value. It will be reset to default } - + if (!strcasecmp(name,"enable_client_deprecate_eof")) { + if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { + variables.enable_client_deprecate_eof=true; + return true; + } + if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { + variables.enable_client_deprecate_eof=false; + return true; + } + return false; + } + if (!strcasecmp(name,"enable_server_deprecate_eof")) { + if (strcasecmp(value,"true")==0 || strcasecmp(value,"1")==0) { + variables.enable_server_deprecate_eof=true; + return true; + } + if (strcasecmp(value,"false")==0 || strcasecmp(value,"0")==0) { + variables.enable_server_deprecate_eof=false; + return true; + } + return false; + } if (!strncmp(name,"default_",8)) { for (int i=0; iget_variable_int((char *)"show_processlist_extended"); mysql_thread___servers_stats=(bool)GloMTH->get_variable_int((char *)"servers_stats"); mysql_thread___default_reconnect=(bool)GloMTH->get_variable_int((char *)"default_reconnect"); + mysql_thread___enable_client_deprecate_eof=(bool)GloMTH->get_variable_int((char *)"enable_client_deprecate_eof"); + mysql_thread___enable_server_deprecate_eof=(bool)GloMTH->get_variable_int((char *)"enable_server_deprecate_eof"); #ifdef DEBUG mysql_thread___session_debug=(bool)GloMTH->get_variable_int((char *)"session_debug"); #endif /* DEBUG */ diff --git a/lib/mysql_connection.cpp b/lib/mysql_connection.cpp index 7046ccec5..6e27fbd6a 100644 --- a/lib/mysql_connection.cpp +++ b/lib/mysql_connection.cpp @@ -605,6 +605,13 @@ void MySQL_Connection::connect_start() { } } + // set 'CLIENT_DEPRECATE_EOF' flag if explicitly stated by 'mysql-enable_server_deprecate_eof'. + // Capability is disabled by default in 'mariadb_client', so setting this option is not optional + // for having 'CLIENT_DEPRECATE_EOF' in the connection to be stablished. + if (mysql_thread___enable_server_deprecate_eof) { + mysql->options.client_flag |= CLIENT_DEPRECATE_EOF; + } + char *auth_password=NULL; if (userinfo->password) { if (userinfo->password[0]=='*') { // we don't have the real password, let's pass sha1