diff --git a/include/MySQL_Session.h b/include/MySQL_Session.h index 4d3b4e146..d2ce03fe6 100644 --- a/include/MySQL_Session.h +++ b/include/MySQL_Session.h @@ -114,11 +114,33 @@ class MySQL_Session bool handler_again___verify_backend_sql_log_bin(); bool handler_again___verify_backend_sql_mode(); bool handler_again___verify_backend_time_zone(); + bool handler_again___verify_backend_isolation_level(); + bool handler_again___verify_backend_transaction_read(); + bool handler_again___verify_backend_character_set_results(); + bool handler_again___verify_backend_session_track_gtids(); + bool handler_again___verify_backend_sql_auto_is_null(); + bool handler_again___verify_backend_sql_select_limit(); + bool handler_again___verify_backend_sql_safe_updates(); + bool handler_again___verify_backend_collation_connection(); + bool handler_again___verify_backend_net_write_timeout(); + bool handler_again___verify_backend_max_join_size(); + bool handler_again___verify_backend__generic_variable(uint32_t *be_int, char **be_var, char *def, uint32_t *fe_int, char *fe_var, enum session_status next_sess_status); bool handler_again___status_SETTING_INIT_CONNECT(int *); bool handler_again___status_SETTING_LDAP_USER_VARIABLE(int *); bool handler_again___status_SETTING_SQL_LOG_BIN(int *); bool handler_again___status_SETTING_SQL_MODE(int *); bool handler_again___status_SETTING_TIME_ZONE(int *); + bool handler_again___status_SETTING_ISOLATION_LEVEL(int *); + bool handler_again___status_SETTING_TRANSACTION_READ(int *); + bool handler_again___status_SETTING_CHARACTER_SET_RESULTS(int *); + bool handler_again___status_SETTING_SESSION_TRACK_GTIDS(int *); + bool handler_again___status_SETTING_SQL_AUTO_IS_NULL(int *); + bool handler_again___status_SETTING_SQL_SELECT_LIMIT(int *); + bool handler_again___status_SETTING_SQL_SAFE_UPDATES(int *); + bool handler_again___status_SETTING_COLLATION_CONNECTION(int *); + bool handler_again___status_SETTING_NET_WRITE_TIMEOUT(int *); + bool handler_again___status_SETTING_MAX_JOIN_SIZE(int *); + bool handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, char *var_name, char *var_value, bool no_quote=false, bool set_transaction=false); bool handler_again___status_CHANGING_SCHEMA(int *); bool handler_again___status_CONNECTING_SERVER(int *); bool handler_again___status_CHANGING_USER_SERVER(int *); @@ -245,6 +267,7 @@ class MySQL_Session void finishQuery(MySQL_Data_Stream *myds, MySQL_Connection *myconn, bool); void generate_proxysql_internal_session_json(json &); bool known_query_for_locked_on_hostgroup(uint64_t); + void unable_to_parse_set_statement(bool *); }; #define KILL_QUERY 1 diff --git a/include/MySQL_Thread.h b/include/MySQL_Thread.h index 6fb1a631d..ae964c252 100644 --- a/include/MySQL_Thread.h +++ b/include/MySQL_Thread.h @@ -19,6 +19,16 @@ #define MYSQL_DEFAULT_SQL_MODE "" #define MYSQL_DEFAULT_TIME_ZONE "SYSTEM" +#define MYSQL_DEFAULT_ISOLATION_LEVEL "READ COMMITTED" +#define MYSQL_DEFAULT_TRANSACTION_READ "WRITE" +#define MYSQL_DEFAULT_CHARACTER_SET_RESULTS "NULL" +#define MYSQL_DEFAULT_SESSION_TRACK_GTIDS "OFF" +#define MYSQL_DEFAULT_SQL_AUTO_IS_NULL "OFF" +#define MYSQL_DEFAULT_SQL_SELECT_LIMIT "DEFAULT" +#define MYSQL_DEFAULT_SQL_SAFE_UPDATES "OFF" +#define MYSQL_DEFAULT_COLLATION_CONNECTION "" +#define MYSQL_DEFAULT_NET_WRITE_TIMEOUT "60" +#define MYSQL_DEFAULT_MAX_JOIN_SIZE "18446744073709551615" static unsigned int near_pow_2 (unsigned int n) { unsigned int i = 1; @@ -443,6 +453,16 @@ class MySQL_Threads_Handler char *add_ldap_user_comment; char *default_sql_mode; char *default_time_zone; + char *default_isolation_level; + char *default_transaction_read; + char *default_character_set_results; + char *default_session_track_gtids; + char *default_sql_auto_is_null; + char *default_sql_select_limit; + char *default_sql_safe_updates; + char *default_collation_connection; + char *default_net_write_timeout; + char *default_max_join_size; #ifdef DEBUG bool session_debug; #endif /* DEBUG */ diff --git a/include/mysql_connection.h b/include/mysql_connection.h index a83f9bb3d..93a45c4b2 100644 --- a/include/mysql_connection.h +++ b/include/mysql_connection.h @@ -44,12 +44,42 @@ class MySQL_Connection { char *time_zone; uint32_t sql_mode_int; uint32_t time_zone_int; + uint32_t character_set_results_int; + uint32_t isolation_level_int; + uint32_t transaction_read_int; + uint32_t session_track_gtids_int; + uint32_t sql_auto_is_null_int; + uint32_t sql_select_limit_int; + uint32_t sql_safe_updates_int; + uint32_t collation_connection_int; + uint32_t net_write_timeout_int; + uint32_t max_join_size_int; uint32_t max_allowed_pkt; uint32_t server_capabilities; uint32_t client_flag; unsigned int compression_min_length; char *init_connect; bool init_connect_sent; + char * character_set_results; + char * isolation_level; + char * transaction_read; + char * session_track_gtids; + char * sql_auto_is_null; + char * sql_select_limit; + char * sql_safe_updates; + char * collation_connection; + char * net_write_timeout; + char * max_join_size; + bool isolation_level_sent; + bool transaction_read_sent; + bool character_set_results_sent; + bool session_track_gtids_sent; + bool sql_auto_is_null_sent; + bool sql_select_limit_sent; + bool sql_safe_updates_sent; + bool collation_connection_sent; + bool net_write_timeout_sent; + bool max_join_size_sent; bool sql_mode_sent; char *ldap_user_variable; char *ldap_user_variable_value; diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h index a54ba1a07..0e332b037 100644 --- a/include/proxysql_structs.h +++ b/include/proxysql_structs.h @@ -152,6 +152,16 @@ enum session_status { SETTING_SQL_LOG_BIN, SETTING_SQL_MODE, SETTING_TIME_ZONE, + SETTING_ISOLATION_LEVEL, + SETTING_TRANSACTION_READ, + SETTING_CHARACTER_SET_RESULTS, + SETTING_SESSION_TRACK_GTIDS, + SETTING_SQL_AUTO_IS_NULL, + SETTING_SQL_SELECT_LIMIT, + SETTING_SQL_SAFE_UPDATES, + SETTING_COLLATION_CONNECTION, + SETTING_NET_WRITE_TIMEOUT, + SETTING_MAX_JOIN_SIZE, FAST_FORWARD, PROCESSING_STMT_PREPARE, PROCESSING_STMT_EXECUTE, @@ -612,6 +622,16 @@ __thread char *mysql_thread___init_connect; __thread char *mysql_thread___ldap_user_variable; __thread char *mysql_thread___default_sql_mode; __thread char *mysql_thread___default_time_zone; +__thread char *mysql_thread___default_isolation_level; +__thread char *mysql_thread___default_transaction_read; +__thread char *mysql_thread___default_character_set_results; +__thread char *mysql_thread___default_session_track_gtids; +__thread char *mysql_thread___default_sql_auto_is_null; +__thread char *mysql_thread___default_sql_select_limit; +__thread char *mysql_thread___default_sql_safe_updates; +__thread char *mysql_thread___default_collation_connection; +__thread char *mysql_thread___default_net_write_timeout; +__thread char *mysql_thread___default_max_join_size; __thread int mysql_thread___max_allowed_packet; __thread bool mysql_thread___use_tcp_keepalive; __thread int mysql_thread___tcp_keepalive_time; @@ -748,6 +768,16 @@ extern __thread char *mysql_thread___init_connect; extern __thread char *mysql_thread___ldap_user_variable; extern __thread char *mysql_thread___default_sql_mode; extern __thread char *mysql_thread___default_time_zone; +extern __thread char *mysql_thread___default_isolation_level; +extern __thread char *mysql_thread___default_transaction_read; +extern __thread char *mysql_thread___default_character_set_results; +extern __thread char *mysql_thread___default_session_track_gtids; +extern __thread char *mysql_thread___default_sql_auto_is_null; +extern __thread char *mysql_thread___default_sql_select_limit; +extern __thread char *mysql_thread___default_sql_safe_updates; +extern __thread char *mysql_thread___default_collation_connection; +extern __thread char *mysql_thread___default_net_write_timeout; +extern __thread char *mysql_thread___default_max_join_size; extern __thread int mysql_thread___max_allowed_packet; extern __thread bool mysql_thread___use_tcp_keepalive; extern __thread int mysql_thread___tcp_keepalive_time; diff --git a/include/set_parser.h b/include/set_parser.h index 8a06e78f5..9fc889c56 100644 --- a/include/set_parser.h +++ b/include/set_parser.h @@ -9,7 +9,8 @@ class SetParser { std::string query; public: SetParser(std::string q); - std::map> parse(); + std::map> parse1(); + std::map> parse2(); }; diff --git a/lib/MySQL_HostGroups_Manager.cpp b/lib/MySQL_HostGroups_Manager.cpp index fc4ed3082..7c8dcb0dc 100644 --- a/lib/MySQL_HostGroups_Manager.cpp +++ b/lib/MySQL_HostGroups_Manager.cpp @@ -2777,24 +2777,32 @@ void MySQL_HostGroups_Manager::destroy_MyConn_from_pool(MySQL_Connection *c, boo // probably because there is a long running query // therefore we will try to kill the connection if (mysql_thread___kill_backend_connection_when_disconnect) { - MySQL_Connection_userinfo *ui=c->userinfo; - char *auth_password=NULL; - if (ui->password) { - if (ui->password[0]=='*') { // we don't have the real password, let's pass sha1 - auth_password=ui->sha1_pass; - } else { - auth_password=ui->password; - } - } - KillArgs *ka = new KillArgs(ui->username, auth_password, c->parent->address, c->parent->port, c->mysql->thread_id, KILL_CONNECTION, NULL); - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_attr_setstacksize (&attr, 256*1024); - pthread_t pt; - if (pthread_create(&pt, &attr, &kill_query_thread, ka) != 0) { - proxy_error("Thread creation\n"); - assert(0); + int myerr=mysql_errno(c->mysql); + switch (myerr) { + case 1231: + break; + default: { + MySQL_Connection_userinfo *ui=c->userinfo; + char *auth_password=NULL; + if (ui->password) { + if (ui->password[0]=='*') { // we don't have the real password, let's pass sha1 + auth_password=ui->sha1_pass; + } else { + auth_password=ui->password; + } + } + KillArgs *ka = new KillArgs(ui->username, auth_password, c->parent->address, c->parent->port, c->mysql->thread_id, KILL_CONNECTION, NULL); + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setstacksize (&attr, 256*1024); + pthread_t pt; + if (pthread_create(&pt, &attr, &kill_query_thread, ka) != 0) { + proxy_error("Thread creation\n"); + assert(0); + } + } + break; } } } diff --git a/lib/MySQL_Protocol.cpp b/lib/MySQL_Protocol.cpp index c4512c8fb..e2d41b371 100644 --- a/lib/MySQL_Protocol.cpp +++ b/lib/MySQL_Protocol.cpp @@ -569,6 +569,7 @@ bool MySQL_Protocol::generate_pkt_ERR(bool send, void **ptr, unsigned int *len, case STATE_CLIENT_HANDSHAKE: case STATE_QUERY_SENT_DS: case STATE_QUERY_SENT_NET: + case STATE_ERR: (*myds)->DSS=STATE_ERR; break; case STATE_OK: @@ -1475,7 +1476,7 @@ bool MySQL_Protocol::process_pkt_handshake_response(unsigned char *pkt, unsigned #endif bool ret=false; uint8_t charset; - uint32_t capabilities; + uint32_t capabilities = 0; uint32_t max_pkt; uint32_t pass_len; unsigned char *user=NULL; diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index a9b78bc40..20c59352a 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -22,6 +22,25 @@ #define EXPMARIA + +static inline char is_digit(char c) { + if(c >= '0' && c <= '9') + return 1; + return 0; +} +static inline char is_normal_char(char c) { + if(c >= 'a' && c <= 'z') + return 1; + if(c >= 'A' && c <= 'Z') + return 1; + if(c >= '0' && c <= '9') + return 1; + if(c == '$' || c == '_') + return 1; + return 0; +} + + extern const MARIADB_CHARSET_INFO * proxysql_find_charset_name(const char * const name); extern MARIADB_CHARSET_INFO * proxysql_find_charset_collate_names(const char *csname, const char *collatename); @@ -818,18 +837,21 @@ bool MySQL_Session::handler_SetAutocommit(PtrSize_t *pkt) { // there is an active transaction, we need to forward it // because this can potentially close the transaction autocommit=true; + client_myds->myconn->set_autocommit(autocommit); autocommit_on_hostgroup=FindOneActiveTransaction(); return false; } else { // as there is no active transaction, we do no need to forward it // just change internal state autocommit=true; + client_myds->myconn->set_autocommit(autocommit); goto __ret_autocommit_OK; } } if (fd==0) { autocommit=false; // we set it, no matter if already set or not + client_myds->myconn->set_autocommit(autocommit); // it turned out I was wrong // set autocommit=0 has no effect if there is an acrive transaction // therefore, we never forward set autocommit = 0 @@ -904,6 +926,16 @@ void MySQL_Session::generate_proxysql_internal_session_json(json &j) { j["transaction_persistent"] = transaction_persistent; j["conn"]["sql_mode"] = ( client_myds->myconn->options.sql_mode ? client_myds->myconn->options.sql_mode : "") ; j["conn"]["time_zone"] = ( client_myds->myconn->options.time_zone ? client_myds->myconn->options.time_zone : "") ; + j["conn"]["isolation_level"] = ( client_myds->myconn->options.isolation_level ? client_myds->myconn->options.isolation_level : "") ; + j["conn"]["transaction_read"] = ( client_myds->myconn->options.transaction_read ? client_myds->myconn->options.transaction_read : "") ; + j["conn"]["character_set_results"] = ( client_myds->myconn->options.character_set_results ? client_myds->myconn->options.character_set_results : "") ; + j["conn"]["session_track_gtids"] = ( client_myds->myconn->options.session_track_gtids ? client_myds->myconn->options.session_track_gtids : "") ; + j["conn"]["sql_auto_is_null"] = ( client_myds->myconn->options.sql_auto_is_null ? client_myds->myconn->options.sql_auto_is_null : "") ; + j["conn"]["sql_select_limit"] = ( client_myds->myconn->options.sql_select_limit ? client_myds->myconn->options.sql_select_limit : "") ; + j["conn"]["sql_safe_updates"] = ( client_myds->myconn->options.sql_safe_updates ? client_myds->myconn->options.sql_safe_updates : "") ; + j["conn"]["collation_connection"] = ( client_myds->myconn->options.collation_connection ? client_myds->myconn->options.collation_connection : "") ; + j["conn"]["net_write_timeout"] = ( client_myds->myconn->options.net_write_timeout ? client_myds->myconn->options.net_write_timeout : "") ; + j["conn"]["max_join_size"] = ( client_myds->myconn->options.max_join_size ? client_myds->myconn->options.max_join_size : "") ; j["conn"]["charset"] = client_myds->myconn->options.charset; j["conn"]["sql_log_bin"] = client_myds->myconn->options.sql_log_bin; j["conn"]["autocommit"] = client_myds->myconn->options.autocommit; @@ -948,6 +980,16 @@ void MySQL_Session::generate_proxysql_internal_session_json(json &j) { j["backends"][i]["conn"]["sql_mode"] = ( _myconn->options.sql_mode ? _myconn->options.sql_mode : "") ; j["backends"][i]["conn"]["sql_mode_sent"] = _myds->myconn->options.sql_mode_sent; j["backends"][i]["conn"]["time_zone"] = ( _myconn->options.time_zone ? _myconn->options.time_zone : "") ; + j["backends"][i]["conn"]["isolation_level"] = ( _myconn->options.isolation_level ? _myconn->options.isolation_level : "") ; + j["backends"][i]["conn"]["transaction_read"] = ( _myconn->options.transaction_read ? _myconn->options.transaction_read : "") ; + j["backends"][i]["conn"]["character_set_results"] = ( _myconn->options.character_set_results ? _myconn->options.character_set_results : "") ; + j["backends"][i]["conn"]["session_track_gtids"] = ( _myconn->options.session_track_gtids ? _myconn->options.session_track_gtids : "") ; + j["backends"][i]["conn"]["sql_auto_is_null"] = ( _myconn->options.sql_auto_is_null ? _myconn->options.sql_auto_is_null : "") ; + j["backends"][i]["conn"]["sql_select_limit"] = ( _myconn->options.sql_select_limit ? _myconn->options.sql_select_limit : "") ; + j["backends"][i]["conn"]["sql_safe_updates"] = ( _myconn->options.sql_safe_updates ? _myconn->options.sql_safe_updates : "") ; + j["backends"][i]["conn"]["collation_connection"] = ( _myconn->options.collation_connection ? _myconn->options.collation_connection : "") ; + j["backends"][i]["conn"]["net_write_timeout"] = ( _myconn->options.net_write_timeout ? _myconn->options.net_write_timeout : "") ; + j["backends"][i]["conn"]["max_join_size"] = ( _myconn->options.max_join_size ? _myconn->options.max_join_size : "") ; //j["backend"][i]["conn"]["charset"] = _myds->myconn->options.charset; // not used for backend j["backends"][i]["conn"]["sql_log_bin"] = _myconn->options.sql_log_bin; j["backends"][i]["conn"]["init_connect"] = ( _myconn->options.init_connect ? _myconn->options.init_connect : ""); @@ -1515,6 +1557,7 @@ void MySQL_Session::handler_again___new_thread_to_kill_connection() { #define NEXT_IMMEDIATE_NEW(new_st) do { set_status(new_st); return true; } while (0) bool MySQL_Session::handler_again___verify_backend_charset() { + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client charset: %d , backend charset: %d\n", this, client_myds->myconn->options.charset, mybe->server_myds->myconn->mysql->charset->nr); if (client_myds->myconn->options.charset != mybe->server_myds->myconn->mysql->charset->nr) { //previous_status.push(PROCESSING_QUERY); switch(status) { // this switch can be replaced with a simple previous_status.push(status), but it is here for readibility @@ -1559,74 +1602,70 @@ bool MySQL_Session::handler_again___verify_backend_sql_log_bin() { } bool MySQL_Session::handler_again___verify_backend_sql_mode() { - if (mybe->server_myds->myconn->options.sql_mode_int==0) { - // it is the first time we use this backend. Set sql_mode to default - if (mybe->server_myds->myconn->options.sql_mode) { - free(mybe->server_myds->myconn->options.sql_mode); - mybe->server_myds->myconn->options.sql_mode=NULL; - } - mybe->server_myds->myconn->options.sql_mode=strdup(mysql_thread___default_sql_mode); - uint32_t sql_mode_int=SpookyHash::Hash32(mybe->server_myds->myconn->options.sql_mode,strlen(mybe->server_myds->myconn->options.sql_mode),10); - mybe->server_myds->myconn->options.sql_mode_int=sql_mode_int; - } - if (client_myds->myconn->options.sql_mode_int) { + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.sql_mode, mybe->server_myds->myconn->options.sql_mode); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.sql_mode_int, + &mybe->server_myds->myconn->options.sql_mode, + mysql_thread___default_sql_mode, + &client_myds->myconn->options.sql_mode_int, + client_myds->myconn->options.sql_mode, + SETTING_SQL_MODE + ); + return ret; +/* + // for sql_mode we also set sql_mode_sent . Doesn't seem used tho. + // snippet, for reference if ( (client_myds->myconn->options.sql_mode_int != mybe->server_myds->myconn->options.sql_mode_int) || (mybe->server_myds->myconn->options.sql_mode_sent == false) ) { mybe->server_myds->myconn->options.sql_mode_sent = true; - { - mybe->server_myds->myconn->options.sql_mode_int = client_myds->myconn->options.sql_mode_int; - if (mybe->server_myds->myconn->options.sql_mode) { - free(mybe->server_myds->myconn->options.sql_mode); - mybe->server_myds->myconn->options.sql_mode=NULL; - if (client_myds->myconn->options.sql_mode) { - mybe->server_myds->myconn->options.sql_mode=strdup(client_myds->myconn->options.sql_mode); - } - } - } - switch(status) { // this switch can be replaced with a simple previous_status.push(status), but it is here for readibility - case PROCESSING_QUERY: - previous_status.push(PROCESSING_QUERY); - break; - case PROCESSING_STMT_PREPARE: - previous_status.push(PROCESSING_STMT_PREPARE); - break; - case PROCESSING_STMT_EXECUTE: - previous_status.push(PROCESSING_STMT_EXECUTE); - break; - default: - assert(0); - break; - } - NEXT_IMMEDIATE_NEW(SETTING_SQL_MODE); - } - } - return false; +*/ + } bool MySQL_Session::handler_again___verify_backend_time_zone() { - if (mybe->server_myds->myconn->options.time_zone_int==0) { - // it is the first time we use this backend. Set time_zone to default - if (mybe->server_myds->myconn->options.time_zone) { - free(mybe->server_myds->myconn->options.time_zone); - mybe->server_myds->myconn->options.time_zone=NULL; + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.time_zone, mybe->server_myds->myconn->options.time_zone); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.time_zone_int, + &mybe->server_myds->myconn->options.time_zone, + mysql_thread___default_time_zone, + &client_myds->myconn->options.time_zone_int, + client_myds->myconn->options.time_zone, + SETTING_TIME_ZONE + ); + return ret; +} + +bool MySQL_Session::handler_again___verify_backend__generic_variable(uint32_t *be_int, char **be_var, char *def, uint32_t *fe_int, char *fe_var, enum session_status next_sess_status) { + // be_int = backend int (hash) + // be_var = backend value + // def = default + // fe_int = frontend int (has) + // fe_var = frontend value + if (*be_int == 0) { + // it is the first time we use this backend. Set value to default + if (*be_var) { + free(*be_var); + *be_var = NULL; } - mybe->server_myds->myconn->options.time_zone=strdup(mysql_thread___default_time_zone); - uint32_t time_zone_int=SpookyHash::Hash32(mybe->server_myds->myconn->options.time_zone,strlen(mybe->server_myds->myconn->options.time_zone),10); - mybe->server_myds->myconn->options.time_zone_int=time_zone_int; + *be_var = strdup(def); + uint32_t tmp_int = SpookyHash::Hash32(*be_var, strlen(*be_var), 10); + *be_int = tmp_int; } - if (client_myds->myconn->options.time_zone_int) { - if (client_myds->myconn->options.time_zone_int != mybe->server_myds->myconn->options.time_zone_int) { + if (*fe_int) { + if (*fe_int != *be_int) { { - mybe->server_myds->myconn->options.time_zone_int = client_myds->myconn->options.time_zone_int; - if (mybe->server_myds->myconn->options.time_zone) { - free(mybe->server_myds->myconn->options.time_zone); - mybe->server_myds->myconn->options.time_zone=NULL; - if (client_myds->myconn->options.time_zone) { - mybe->server_myds->myconn->options.time_zone=strdup(client_myds->myconn->options.time_zone); - } + *be_int = *fe_int; + if (*be_var) { + free(*be_var); + *be_var = NULL; + } + if (fe_var) { + *be_var = strdup(fe_var); } } switch(status) { // this switch can be replaced with a simple previous_status.push(status), but it is here for readibility @@ -1643,12 +1682,151 @@ bool MySQL_Session::handler_again___verify_backend_time_zone() { assert(0); break; } - NEXT_IMMEDIATE_NEW(SETTING_TIME_ZONE); + NEXT_IMMEDIATE_NEW(next_sess_status); } } return false; } +bool MySQL_Session::handler_again___verify_backend_isolation_level() { + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.isolation_level, mybe->server_myds->myconn->options.isolation_level); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.isolation_level_int, + &mybe->server_myds->myconn->options.isolation_level, + mysql_thread___default_isolation_level, + &client_myds->myconn->options.isolation_level_int, + client_myds->myconn->options.isolation_level, + SETTING_ISOLATION_LEVEL + ); + return ret; +} + +bool MySQL_Session::handler_again___verify_backend_transaction_read() { + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.transaction_read, mybe->server_myds->myconn->options.transaction_read); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.transaction_read_int, + &mybe->server_myds->myconn->options.transaction_read, + mysql_thread___default_transaction_read, + &client_myds->myconn->options.transaction_read_int, + client_myds->myconn->options.transaction_read, + SETTING_TRANSACTION_READ + ); + return ret; +} + +bool MySQL_Session::handler_again___verify_backend_character_set_results() { + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.character_set_results, mybe->server_myds->myconn->options.character_set_results); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.character_set_results_int, + &mybe->server_myds->myconn->options.character_set_results, + mysql_thread___default_character_set_results, + &client_myds->myconn->options.character_set_results_int, + client_myds->myconn->options.character_set_results, + SETTING_CHARACTER_SET_RESULTS + ); + return ret; +} + +bool MySQL_Session::handler_again___verify_backend_session_track_gtids() { + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.session_track_gtids, mybe->server_myds->myconn->options.session_track_gtids); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.session_track_gtids_int, + &mybe->server_myds->myconn->options.session_track_gtids, + mysql_thread___default_session_track_gtids, + &client_myds->myconn->options.session_track_gtids_int, + client_myds->myconn->options.session_track_gtids, + SETTING_SESSION_TRACK_GTIDS + ); + return ret; +} + +bool MySQL_Session::handler_again___verify_backend_sql_auto_is_null() { + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.sql_auto_is_null, mybe->server_myds->myconn->options.sql_auto_is_null); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.sql_auto_is_null_int, + &mybe->server_myds->myconn->options.sql_auto_is_null, + mysql_thread___default_sql_auto_is_null, + &client_myds->myconn->options.sql_auto_is_null_int, + client_myds->myconn->options.sql_auto_is_null, + SETTING_SQL_AUTO_IS_NULL + ); + return ret; +} + +bool MySQL_Session::handler_again___verify_backend_sql_select_limit() { + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.sql_select_limit, mybe->server_myds->myconn->options.sql_select_limit); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.sql_select_limit_int, + &mybe->server_myds->myconn->options.sql_select_limit, + mysql_thread___default_sql_select_limit, + &client_myds->myconn->options.sql_select_limit_int, + client_myds->myconn->options.sql_select_limit, + SETTING_SQL_SELECT_LIMIT + ); + return ret; +} + +bool MySQL_Session::handler_again___verify_backend_sql_safe_updates() { + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.sql_safe_updates, mybe->server_myds->myconn->options.sql_safe_updates); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.sql_safe_updates_int, + &mybe->server_myds->myconn->options.sql_safe_updates, + mysql_thread___default_sql_safe_updates, + &client_myds->myconn->options.sql_safe_updates_int, + client_myds->myconn->options.sql_safe_updates, + SETTING_SQL_SAFE_UPDATES + ); + return ret; +} + +bool MySQL_Session::handler_again___verify_backend_collation_connection() { + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.collation_connection, mybe->server_myds->myconn->options.collation_connection); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.collation_connection_int, + &mybe->server_myds->myconn->options.collation_connection, + mysql_thread___default_collation_connection, + &client_myds->myconn->options.collation_connection_int, + client_myds->myconn->options.collation_connection, + SETTING_COLLATION_CONNECTION + ); + return ret; +} + +bool MySQL_Session::handler_again___verify_backend_net_write_timeout() { + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.net_write_timeout, mybe->server_myds->myconn->options.net_write_timeout); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.net_write_timeout_int, + &mybe->server_myds->myconn->options.net_write_timeout, + mysql_thread___default_net_write_timeout, + &client_myds->myconn->options.net_write_timeout_int, + client_myds->myconn->options.net_write_timeout, + SETTING_NET_WRITE_TIMEOUT + ); + return ret; +} + +bool MySQL_Session::handler_again___verify_backend_max_join_size() { + bool ret = false; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->options.max_join_size, mybe->server_myds->myconn->options.max_join_size); + ret = handler_again___verify_backend__generic_variable( + &mybe->server_myds->myconn->options.max_join_size_int, + &mybe->server_myds->myconn->options.max_join_size, + mysql_thread___default_max_join_size, + &client_myds->myconn->options.max_join_size_int, + client_myds->myconn->options.max_join_size, + SETTING_MAX_JOIN_SIZE + ); + return ret; +} bool MySQL_Session::handler_again___verify_init_connect() { if (mybe->server_myds->myconn->options.init_connect_sent==false) { @@ -1733,6 +1911,7 @@ bool MySQL_Session::handler_again___verify_backend_autocommit() { if (mysql_thread___forward_autocommit == true) { return false; } + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %d , backend: %d\n", this, client_myds->myconn->options.autocommit, mybe->server_myds->myconn->options.autocommit); if (autocommit != mybe->server_myds->myconn->IsAutoCommit()) { // see case #485 if (mysql_thread___enforce_autocommit_on_reads == false && autocommit == false) { @@ -1792,12 +1971,15 @@ bool MySQL_Session::handler_again___verify_backend_autocommit() { } } } else { // mysql_thread___enforce_autocommit_on_reads == true + // this code seems wrong. Removed +/* if (mybe->server_myds->myconn->IsActiveTransaction() == false) { if (status == PROCESSING_QUERY) { previous_status.push(PROCESSING_QUERY); NEXT_IMMEDIATE_NEW(CHANGING_AUTOCOMMIT); } } +*/ } } } @@ -1806,6 +1988,8 @@ bool MySQL_Session::handler_again___verify_backend_autocommit() { bool MySQL_Session::handler_again___verify_backend_user_schema() { MySQL_Data_Stream *myds=mybe->server_myds; + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->userinfo->username, mybe->server_myds->myconn->userinfo->username); + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %s , backend: %s\n", this, client_myds->myconn->userinfo->schemaname, mybe->server_myds->myconn->userinfo->schemaname); if (client_myds->myconn->userinfo->hash!=mybe->server_myds->myconn->userinfo->hash) { if (strcmp(client_myds->myconn->userinfo->username,myds->myconn->userinfo->username)) { //previous_status.push(PROCESSING_QUERY); @@ -1862,6 +2046,7 @@ bool MySQL_Session::handler_again___status_SETTING_INIT_CONNECT(int *_rc) { if (rc==0) { myds->revents|=POLLOUT; // we also set again POLLOUT to send a query immediately! //myds->free_mysql_real_query(); + myds->DSS = STATE_MARIADB_GENERIC; st=previous_status.top(); previous_status.pop(); NEXT_IMMEDIATE_NEW(st); @@ -1921,6 +2106,7 @@ bool MySQL_Session::handler_again___status_SETTING_LDAP_USER_VARIABLE(int *_rc) ) { // nothing to do myds->revents|=POLLOUT; // we also set again POLLOUT to send a query immediately! //myds->free_mysql_real_query(); + myds->DSS = STATE_MARIADB_GENERIC; st=previous_status.top(); previous_status.pop(); NEXT_IMMEDIATE_NEW(st); @@ -1950,6 +2136,7 @@ bool MySQL_Session::handler_again___status_SETTING_LDAP_USER_VARIABLE(int *_rc) if (rc==0) { myds->revents|=POLLOUT; // we also set again POLLOUT to send a query immediately! //myds->free_mysql_real_query(); + myds->DSS = STATE_MARIADB_GENERIC; st=previous_status.top(); previous_status.pop(); NEXT_IMMEDIATE_NEW(st); @@ -2025,6 +2212,7 @@ bool MySQL_Session::handler_again___status_SETTING_SQL_LOG_BIN(int *_rc) { myconn->set_status_sql_log_bin0(false); } myds->revents|=POLLOUT; // we also set again POLLOUT to send a query immediately! + myds->DSS = STATE_MARIADB_GENERIC; st=previous_status.top(); previous_status.pop(); NEXT_IMMEDIATE_NEW(st); @@ -2067,6 +2255,17 @@ bool MySQL_Session::handler_again___status_SETTING_SQL_LOG_BIN(int *_rc) { return ret; } +bool MySQL_Session::handler_again___status_SETTING_SQL_MODE(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SQL_MODE", mybe->server_myds->myconn->options.sql_mode); + return ret; +} + +/* FIXME: this old code hardcoded the handling of issue 1738 +// this seems unnecessary/redundant +// leaving the code for further reference, to be removed later +// FIXME bool MySQL_Session::handler_again___status_SETTING_SQL_MODE(int *_rc) { bool ret=false; assert(mybe->server_myds->myconn); @@ -2167,9 +2366,10 @@ bool MySQL_Session::handler_again___status_SETTING_SQL_MODE(int *_rc) { } return ret; } +*/ -bool MySQL_Session::handler_again___status_SETTING_TIME_ZONE(int *_rc) { - bool ret=false; +bool MySQL_Session::handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, char *var_name, char *var_value, bool no_quote, bool set_transaction) { + bool ret = false; assert(mybe->server_myds->myconn); MySQL_Data_Stream *myds=mybe->server_myds; MySQL_Connection *myconn=myds->myconn; @@ -2182,13 +2382,27 @@ bool MySQL_Session::handler_again___status_SETTING_TIME_ZONE(int *_rc) { unsigned long query_length=0; if (myconn->async_state_machine==ASYNC_IDLE) { char *q = NULL; - if (myconn->options.time_zone[0]=='@') { - q=(char *)"SET TIME_ZONE=%s"; + if (set_transaction==false) { + if (no_quote) { + q=(char *)"SET %s=%s"; + } else { + q=(char *)"SET %s='%s'"; // default + if (var_value[0] && var_value[0]=='@') { + q=(char *)"SET %s=%s";} + if (strncasecmp(var_value,(char *)"CONCAT",6)==0) + q=(char *)"SET %s=%s"; + if (strncasecmp(var_value,(char *)"IFNULL",6)==0) + q=(char *)"SET %s=%s"; + if (strncasecmp(var_value,(char *)"REPLACE",7)==0) + q=(char *)"SET %s=%s"; + } } else { - q=(char *)"SET TIME_ZONE='%s'"; + // NOTE: for now, only SET SESSION is supported + // the calling function is already passing "SESSION TRANSACTION" + q=(char *)"SET %s %s"; } - query=(char *)malloc(strlen(q)+strlen(myconn->options.time_zone)); - sprintf(query,q,myconn->options.time_zone); + query=(char *)malloc(strlen(q)+strlen(var_name)+strlen(var_value)); + sprintf(query,q,var_name, var_value); query_length=strlen(query); } int rc=myconn->async_send_simple_command(myds->revents,query,query_length); @@ -2198,6 +2412,7 @@ bool MySQL_Session::handler_again___status_SETTING_TIME_ZONE(int *_rc) { } if (rc==0) { myds->revents|=POLLOUT; // we also set again POLLOUT to send a query immediately! + myds->DSS = STATE_MARIADB_GENERIC; st=previous_status.top(); previous_status.pop(); NEXT_IMMEDIATE_NEW(st); @@ -2208,10 +2423,10 @@ bool MySQL_Session::handler_again___status_SETTING_TIME_ZONE(int *_rc) { if (myerr >= 2000) { bool retry_conn=false; // client error, serious - proxy_error("Detected a broken connection while setting TIME_ZONE on %s , %d : %d, %s\n", myconn->parent->address, myconn->parent->port, myerr, mysql_error(myconn->mysql)); - //if ((myds->myconn->reusable==true) && ((myds->myprot.prot_status & SERVER_STATUS_IN_TRANS)==0)) { - if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { - retry_conn=true; + proxy_error("Detected a broken connection while setting %s on %s , %d : %d, %s\n", var_name, myconn->parent->address, myconn->parent->port, myerr, mysql_error(myconn->mysql)); + //if ((myds->myconn->reusable==true) && ((myds->myprot.prot_status & SERVER_STATUS_IN_TRANS)==0)) { + if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { + retry_conn=true; } myds->destroy_MySQL_Connection_From_Pool(false); myds->fd=0; @@ -2222,14 +2437,39 @@ bool MySQL_Session::handler_again___status_SETTING_TIME_ZONE(int *_rc) { *_rc=-1; // an error happened, we should destroy the Session return ret; } else { - proxy_warning("Error while setting TIME_ZONE: %d, %s\n", myerr, mysql_error(myconn->mysql)); + proxy_warning("Error while setting %s: %d, %s\n", var_name, myerr, mysql_error(myconn->mysql)); // we won't go back to PROCESSING_QUERY st=previous_status.top(); previous_status.pop(); char sqlstate[10]; sprintf(sqlstate,"%s",mysql_sqlstate(myconn->mysql)); client_myds->myprot.generate_pkt_ERR(true,NULL,NULL,1,mysql_errno(myconn->mysql),sqlstate,mysql_error(myconn->mysql)); - myds->destroy_MySQL_Connection_From_Pool(true); + int myerr=mysql_errno(myconn->mysql); + switch (myerr) { + case 1231: +/* + too complicated code? + if (mysql_thread___multiplexing && (myconn->reusable==true) && myconn->IsActiveTransaction()==false && myconn->MultiplexDisabled()==false) { + myds->DSS=STATE_NOT_INITIALIZED; + if (mysql_thread___autocommit_false_not_reusable && myconn->IsAutoCommit()==false) { + if (mysql_thread___reset_connection_algorithm == 2) { + create_new_session_and_reset_connection(myds); + } else { + myds->destroy_MySQL_Connection_From_Pool(true); + } + } else { + myds->return_MySQL_Connection_To_Pool(); + } + } else { + myconn->async_state_machine=ASYNC_IDLE; + myds->DSS=STATE_MARIADB_GENERIC; + } + break; +*/ + default: + myds->destroy_MySQL_Connection_From_Pool(true); + break; + } myds->fd=0; RequestEnd(myds); } @@ -2240,6 +2480,83 @@ bool MySQL_Session::handler_again___status_SETTING_TIME_ZONE(int *_rc) { return ret; } +bool MySQL_Session::handler_again___status_SETTING_TIME_ZONE(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"TIME_ZONE", mybe->server_myds->myconn->options.time_zone); + return ret; +} + +bool MySQL_Session::handler_again___status_SETTING_ISOLATION_LEVEL(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SESSION TRANSACTION ISOLATION LEVEL", mybe->server_myds->myconn->options.isolation_level, false, true); + return ret; +} + +bool MySQL_Session::handler_again___status_SETTING_TRANSACTION_READ(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SESSION TRANSACTION READ", mybe->server_myds->myconn->options.transaction_read, false, true); + return ret; +} + +bool MySQL_Session::handler_again___status_SETTING_CHARACTER_SET_RESULTS(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"CHARACTER_SET_RESULTS", mybe->server_myds->myconn->options.character_set_results, true); + return ret; +} + +bool MySQL_Session::handler_again___status_SETTING_SESSION_TRACK_GTIDS(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SESSION_TRACK_GTIDS", mybe->server_myds->myconn->options.session_track_gtids, true); + return ret; +} + +bool MySQL_Session::handler_again___status_SETTING_SQL_AUTO_IS_NULL(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SQL_AUTO_IS_NULL", mybe->server_myds->myconn->options.sql_auto_is_null, true); + return ret; +} + +bool MySQL_Session::handler_again___status_SETTING_SQL_SELECT_LIMIT(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SQL_SELECT_LIMIT", mybe->server_myds->myconn->options.sql_select_limit, true); + return ret; +} + +bool MySQL_Session::handler_again___status_SETTING_SQL_SAFE_UPDATES(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"SQL_SAFE_UPDATES", mybe->server_myds->myconn->options.sql_safe_updates, true); + return ret; +} + +bool MySQL_Session::handler_again___status_SETTING_COLLATION_CONNECTION(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"COLLATION_CONNECTION", mybe->server_myds->myconn->options.collation_connection); + return ret; +} + +bool MySQL_Session::handler_again___status_SETTING_NET_WRITE_TIMEOUT(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"NET_WRITE_TIMEOUT", mybe->server_myds->myconn->options.net_write_timeout, true); + return ret; +} + +bool MySQL_Session::handler_again___status_SETTING_MAX_JOIN_SIZE(int *_rc) { + bool ret=false; + assert(mybe->server_myds->myconn); + ret = handler_again___status_SETTING_GENERIC_VARIABLE(_rc, (char *)"MAX_JOIN_SIZE", mybe->server_myds->myconn->options.max_join_size, true); + return ret; +} + bool MySQL_Session::handler_again___status_CHANGING_SCHEMA(int *_rc) { bool ret=false; @@ -2256,6 +2573,7 @@ bool MySQL_Session::handler_again___status_CHANGING_SCHEMA(int *_rc) { if (rc==0) { __sync_fetch_and_add(&MyHGM->status.backend_init_db, 1); myds->myconn->userinfo->set(client_myds->myconn->userinfo); + myds->DSS = STATE_MARIADB_GENERIC; st=previous_status.top(); previous_status.pop(); NEXT_IMMEDIATE_NEW(st); @@ -2542,6 +2860,7 @@ bool MySQL_Session::handler_again___status_CHANGING_CHARSET(int *_rc) { int rc=myconn->async_set_names(myds->revents, client_myds->myconn->options.charset); if (rc==0) { __sync_fetch_and_add(&MyHGM->status.backend_set_names, 1); + myds->DSS = STATE_MARIADB_GENERIC; st=previous_status.top(); previous_status.pop(); NEXT_IMMEDIATE_NEW(st); @@ -2616,6 +2935,7 @@ bool MySQL_Session::handler_again___status_CHANGING_AUTOCOMMIT(int *_rc) { } else { st=previous_status.top(); previous_status.pop(); + myds->DSS = STATE_MARIADB_GENERIC; NEXT_IMMEDIATE_NEW(st); } } @@ -2625,6 +2945,7 @@ bool MySQL_Session::handler_again___status_CHANGING_AUTOCOMMIT(int *_rc) { if (rc==0) { st=previous_status.top(); previous_status.pop(); + myds->DSS = STATE_MARIADB_GENERIC; NEXT_IMMEDIATE_NEW(st); } else { if (rc==-1) { @@ -3443,6 +3764,7 @@ handler_again: goto handler_again; } if (mirror==false) { // do not care about autocommit and charset if mirror + proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , default_HG=%d server_myds DSS=%d , locked_on_HG=%d\n", this, default_hostgroup, mybe->server_myds->DSS, locked_on_hostgroup); if (mybe->server_myds->DSS == STATE_READY || mybe->server_myds->DSS == STATE_MARIADB_GENERIC) { if (handler_again___verify_init_connect()) { goto handler_again; @@ -3452,20 +3774,52 @@ handler_again: goto handler_again; } } - if (handler_again___verify_backend_charset()) { - goto handler_again; - } if (handler_again___verify_backend_autocommit()) { goto handler_again; } - if (handler_again___verify_backend_sql_log_bin()) { - goto handler_again; - } - if (handler_again___verify_backend_sql_mode()) { - goto handler_again; - } - if (handler_again___verify_backend_time_zone()) { - goto handler_again; + if (locked_on_hostgroup == -1) { + if (handler_again___verify_backend_charset()) { + goto handler_again; + } + if (handler_again___verify_backend_sql_log_bin()) { + goto handler_again; + } + if (handler_again___verify_backend_sql_mode()) { + goto handler_again; + } + if (handler_again___verify_backend_time_zone()) { + goto handler_again; + } + if (handler_again___verify_backend_isolation_level()) { + goto handler_again; + } + if (handler_again___verify_backend_transaction_read()) { + goto handler_again; + } + if (handler_again___verify_backend_character_set_results()) { + goto handler_again; + } + if (handler_again___verify_backend_session_track_gtids()) { + goto handler_again; + } + if (handler_again___verify_backend_sql_auto_is_null()) { + goto handler_again; + } + if (handler_again___verify_backend_sql_select_limit()) { + goto handler_again; + } + if (handler_again___verify_backend_sql_safe_updates()) { + goto handler_again; + } + if (handler_again___verify_backend_collation_connection()) { + goto handler_again; + } + if (handler_again___verify_backend_net_write_timeout()) { + goto handler_again; + } + if (handler_again___verify_backend_max_join_size()) { + goto handler_again; + } } } if (status==PROCESSING_STMT_EXECUTE) { @@ -4000,6 +4354,126 @@ handler_again: } break; + case SETTING_ISOLATION_LEVEL: + { + int rc=0; + if (handler_again___status_SETTING_ISOLATION_LEVEL(&rc)) + goto handler_again; // we changed status + if (rc==-1) { // we have an error we can't handle + handler_ret = -1; + return handler_ret; + } + } + break; + + case SETTING_TRANSACTION_READ: + { + int rc=0; + if (handler_again___status_SETTING_TRANSACTION_READ(&rc)) + goto handler_again; // we changed status + if (rc==-1) { // we have an error we can't handle + handler_ret = -1; + return handler_ret; + } + } + break; + + case SETTING_CHARACTER_SET_RESULTS: + { + int rc=0; + if (handler_again___status_SETTING_CHARACTER_SET_RESULTS(&rc)) + goto handler_again; // we changed status + if (rc==-1) { // we have an error we can't handle + handler_ret = -1; + return handler_ret; + } + } + break; + + case SETTING_SESSION_TRACK_GTIDS: + { + int rc=0; + if (handler_again___status_SETTING_SESSION_TRACK_GTIDS(&rc)) + goto handler_again; // we changed status + if (rc==-1) { // we have an error we can't handle + handler_ret = -1; + return handler_ret; + } + } + break; + + case SETTING_SQL_AUTO_IS_NULL: + { + int rc=0; + if (handler_again___status_SETTING_SQL_AUTO_IS_NULL(&rc)) + goto handler_again; // we changed status + if (rc==-1) { // we have an error we can't handle + handler_ret = -1; + return handler_ret; + } + } + break; + + case SETTING_SQL_SELECT_LIMIT: + { + int rc=0; + if (handler_again___status_SETTING_SQL_SELECT_LIMIT(&rc)) + goto handler_again; // we changed status + if (rc==-1) { // we have an error we can't handle + handler_ret = -1; + return handler_ret; + } + } + break; + + case SETTING_SQL_SAFE_UPDATES: + { + int rc=0; + if (handler_again___status_SETTING_SQL_SAFE_UPDATES(&rc)) + goto handler_again; // we changed status + if (rc==-1) { // we have an error we can't handle + handler_ret = -1; + return handler_ret; + } + } + break; + + case SETTING_COLLATION_CONNECTION: + { + int rc=0; + if (handler_again___status_SETTING_COLLATION_CONNECTION(&rc)) + goto handler_again; // we changed status + if (rc==-1) { // we have an error we can't handle + handler_ret = -1; + return handler_ret; + } + } + break; + + case SETTING_NET_WRITE_TIMEOUT: + { + int rc=0; + if (handler_again___status_SETTING_NET_WRITE_TIMEOUT(&rc)) + goto handler_again; // we changed status + if (rc==-1) { // we have an error we can't handle + handler_ret = -1; + return handler_ret; + } + } + break; + + case SETTING_MAX_JOIN_SIZE: + { + int rc=0; + if (handler_again___status_SETTING_MAX_JOIN_SIZE(&rc)) + goto handler_again; // we changed status + if (rc==-1) { // we have an error we can't handle + handler_ret = -1; + return handler_ret; + } + } + break; + case SETTING_INIT_CONNECT: { int rc=0; @@ -4694,6 +5168,8 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C This algorithm will be become obsolete once we implement session tracking for MySQL 5.7+ */ + bool ret = false; + bool exit_after_SetParse = false; unsigned char command_type=*((unsigned char *)pkt->ptr+sizeof(mysql_hdr)); if (qpo->new_query) { // the query was rewritten @@ -4761,7 +5237,8 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C if (CurrentQuery.QueryParserArgs.digest_text) { char *dig=CurrentQuery.QueryParserArgs.digest_text; unsigned int nTrx=NumActiveTransactions(); - if (strncasecmp(dig,(char *)"SET ",4)==0) { + if ((locked_on_hostgroup == -1) && (strncasecmp(dig,(char *)"SET ",4)==0)) { + // this code is executed only if locked_on_hostgroup is not set yet #ifdef DEBUG { string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); @@ -4832,14 +5309,14 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } else { string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); proxy_error("Unable to parse query. If correct, report it as a bug: %s\n", nqn.c_str()); - *lock_hostgroup = true; + unable_to_parse_set_statement(lock_hostgroup); return false; } } } if ( ( - match_regexes && (match_regexes[1]->match(dig) || match_regexes[2]->match(dig)) + match_regexes && (match_regexes[1]->match(dig)) ) || ( strncasecmp(dig,(char *)"SET NAMES", strlen((char *)"SET NAMES")) == 0) @@ -4849,8 +5326,7 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Parsing SET command %s\n", nq.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Parsing SET command = %s\n", nq.c_str()); SetParser parser(nq); - std::map> set = parser.parse(); - bool exit_after_SetParse = false; + std::map> set = parser.parse1(); for(auto it = std::begin(set); it != std::end(set); ++it) { std::string var = it->first; proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET variable %s\n", var.c_str()); @@ -4859,7 +5335,7 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); proxy_error("Unable to parse query. If correct, report it as a bug: %s\n", nqn.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Locking hostgroup for query %s\n", nqn.c_str()); - *lock_hostgroup = true; + unable_to_parse_set_statement(lock_hostgroup); return false; } auto values = std::begin(it->second); @@ -4875,7 +5351,7 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); proxy_error("Unable to parse query. If correct, report it as a bug: %s\n", nqn.c_str()); proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Locking hostgroup for query %s\n", nqn.c_str()); - *lock_hostgroup = true; + unable_to_parse_set_statement(lock_hostgroup); return false; } std::size_t found_at = value1.find("@"); @@ -4888,11 +5364,9 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C // we found a @ . Maybe we need to lock hostgroup proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Found @ in SQL_MODE . v2 = %s\n", v2); if (strncasecmp(v2,(const char *)"@@sql_mode",strlen((const char *)"@@sql_mode"))) { -#ifdef DEBUG - string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); - proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Locking hostgroup for query %s\n", nqn.c_str()); -#endif - *lock_hostgroup = true; + unable_to_parse_set_statement(lock_hostgroup); + free(v1); + return false; } else { v2++; } @@ -4914,18 +5388,85 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C client_myds->myconn->options.sql_mode=strdup(value1.c_str()); if (strcasestr(value1.c_str(), (char *)"NO_BACKSLASH_ESCAPES")) { //goto __exit_set_destination_hostgroup; - exit_after_SetParse = true; } } + exit_after_SetParse = true; + } else if (var == "sql_auto_is_null") { + std::string value1 = *values; + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET sql_auto_is_null value %s\n", value1.c_str()); + int __tmp_value = -1; + if ( + (strcasecmp(value1.c_str(),(char *)"0")==0) || + (strcasecmp(value1.c_str(),(char *)"false")==0) || + (strcasecmp(value1.c_str(),(char *)"off")==0) + ) { + __tmp_value = 0; + } else { + if ( + (strcasecmp(value1.c_str(),(char *)"1")==0) || + (strcasecmp(value1.c_str(),(char *)"true")==0) || + (strcasecmp(value1.c_str(),(char *)"on")==0) + ) { + __tmp_value = 1; + } + } + if (__tmp_value >= 0) { + proxy_debug(PROXY_DEBUG_MYSQL_COM, 7, "Processing SET sql_auto_is_null value %s\n", value1.c_str()); + uint32_t sql_auto_is_null_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); + if (client_myds->myconn->options.sql_auto_is_null_int != sql_auto_is_null_int) { + client_myds->myconn->options.sql_auto_is_null_int = sql_auto_is_null_int; + if (client_myds->myconn->options.sql_auto_is_null) { + free(client_myds->myconn->options.sql_auto_is_null); + } + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection sql_auto_is_null to %s\n", value1.c_str()); + client_myds->myconn->options.sql_auto_is_null=strdup(value1.c_str()); + } + exit_after_SetParse = true; + } else { + unable_to_parse_set_statement(lock_hostgroup); + return false; + } + } else if (var == "sql_safe_updates") { + std::string value1 = *values; + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET sql_safe_updates value %s\n", value1.c_str()); + int __tmp_value = -1; + if ( + (strcasecmp(value1.c_str(),(char *)"0")==0) || + (strcasecmp(value1.c_str(),(char *)"false")==0) || + (strcasecmp(value1.c_str(),(char *)"off")==0) + ) { + __tmp_value = 0; + } else { + if ( + (strcasecmp(value1.c_str(),(char *)"1")==0) || + (strcasecmp(value1.c_str(),(char *)"true")==0) || + (strcasecmp(value1.c_str(),(char *)"on")==0) + ) { + __tmp_value = 1; + } + } + if (__tmp_value >= 0) { + proxy_debug(PROXY_DEBUG_MYSQL_COM, 7, "Processing SET sql_safe_updates value %s\n", value1.c_str()); + uint32_t sql_safe_updates_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); + if (client_myds->myconn->options.sql_safe_updates_int != sql_safe_updates_int) { + client_myds->myconn->options.sql_safe_updates_int = sql_safe_updates_int; + if (client_myds->myconn->options.sql_safe_updates) { + free(client_myds->myconn->options.sql_safe_updates); + } + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection sql_safe_updates to %s\n", value1.c_str()); + client_myds->myconn->options.sql_safe_updates=strdup(value1.c_str()); + } + exit_after_SetParse = true; + } else { + unable_to_parse_set_statement(lock_hostgroup); + return false; + } } else if (var == "autocommit") { std::string value1 = *values; std::size_t found_at = value1.find("@"); if (found_at != std::string::npos) { -#ifdef DEBUG - string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); - proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Locking hostgroup for query %s\n", nqn.c_str()); -#endif - *lock_hostgroup = true; + unable_to_parse_set_statement(lock_hostgroup); + return false; } proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET autocommit value %s\n", value1.c_str()); int __tmp_autocommit = -1; @@ -4957,17 +5498,20 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C // there is an active transaction, we need to forward it // because this can potentially close the transaction autocommit=true; + client_myds->myconn->set_autocommit(autocommit); autocommit_on_hostgroup=FindOneActiveTransaction(); exit_after_SetParse = true; } else { // as there is no active transaction, we do no need to forward it // just change internal state autocommit=true; + client_myds->myconn->set_autocommit(autocommit); } } if (fd==0) { autocommit=false; // we set it, no matter if already set or not + client_myds->myconn->set_autocommit(autocommit); } } else { if (autocommit_handled==true) { @@ -4978,11 +5522,8 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C std::string value1 = *values; std::size_t found_at = value1.find("@"); if (found_at != std::string::npos) { -#ifdef DEBUG - string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); - proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Locking hostgroup for query %s\n", nqn.c_str()); -#endif - *lock_hostgroup = true; + unable_to_parse_set_statement(lock_hostgroup); + return false; } proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET Time Zone value %s\n", value1.c_str()); uint32_t time_zone_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); @@ -4995,15 +5536,166 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection Time zone to %s\n", value1.c_str()); client_myds->myconn->options.time_zone=strdup(value1.c_str()); } + exit_after_SetParse = true; + } else if (var == "session_track_gtids") { + std::string value1 = *values; + if ((strcasecmp(value1.c_str(),"OWN_GTID")==0) || (strcasecmp(value1.c_str(),"OFF")==0)) { + proxy_debug(PROXY_DEBUG_MYSQL_COM, 7, "Processing SET session_track_gtids value %s\n", value1.c_str()); + uint32_t session_track_gtids_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); + if (client_myds->myconn->options.session_track_gtids_int != session_track_gtids_int) { + client_myds->myconn->options.session_track_gtids_int = session_track_gtids_int; + if (client_myds->myconn->options.session_track_gtids) { + free(client_myds->myconn->options.session_track_gtids); + } + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection session_track_gtids to %s\n", value1.c_str()); + client_myds->myconn->options.session_track_gtids=strdup(value1.c_str()); + } + exit_after_SetParse = true; + } else { + unable_to_parse_set_statement(lock_hostgroup); + return false; + } + } else if (var == "max_join_size") { + std::string value1 = *values; + int vl = strlen(value1.c_str()); + const char *v = value1.c_str(); + bool only_digit_chars = true; + for (int i=0; imyconn->options.max_join_size_int != max_join_size_int) { + client_myds->myconn->options.max_join_size_int = max_join_size_int; + if (client_myds->myconn->options.max_join_size) { + free(client_myds->myconn->options.max_join_size); + } + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection max_join_size to %s\n", value1.c_str()); + client_myds->myconn->options.max_join_size=strdup(value1.c_str()); + } + exit_after_SetParse = true; + } else { + unable_to_parse_set_statement(lock_hostgroup); + return false; + } + } else if (var == "net_write_timeout") { + std::string value1 = *values; + int vl = strlen(value1.c_str()); + const char *v = value1.c_str(); + bool only_digit_chars = true; + for (int i=0; imyconn->options.net_write_timeout_int != net_write_timeout_int) { + client_myds->myconn->options.net_write_timeout_int = net_write_timeout_int; + if (client_myds->myconn->options.net_write_timeout) { + free(client_myds->myconn->options.net_write_timeout); + } + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection net_write_timeout to %s\n", value1.c_str()); + client_myds->myconn->options.net_write_timeout=strdup(value1.c_str()); + } + exit_after_SetParse = true; + } else { + unable_to_parse_set_statement(lock_hostgroup); + return false; + } + } else if (var == "sql_select_limit") { + std::string value1 = *values; + int vl = strlen(value1.c_str()); + const char *v = value1.c_str(); + bool only_digit_chars = true; + for (int i=0; imyconn->options.sql_select_limit_int != sql_select_limit_int) { + client_myds->myconn->options.sql_select_limit_int = sql_select_limit_int; + if (client_myds->myconn->options.sql_select_limit) { + free(client_myds->myconn->options.sql_select_limit); + } + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection sql_select_limit to %s\n", value1.c_str()); + client_myds->myconn->options.sql_select_limit=strdup(value1.c_str()); + } + exit_after_SetParse = true; + } else { + unable_to_parse_set_statement(lock_hostgroup); + return false; + } + } else if (var == "collation_connection") { + std::string value1 = *values; + int vl = strlen(value1.c_str()); + const char *v = value1.c_str(); + bool only_normal_chars = true; + for (int i=0; imyconn->options.collation_connection_int != collation_connection_int) { + client_myds->myconn->options.collation_connection_int = collation_connection_int; + if (client_myds->myconn->options.collation_connection) { + free(client_myds->myconn->options.collation_connection); + } + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection collation_connection to %s\n", value1.c_str()); + client_myds->myconn->options.collation_connection=strdup(value1.c_str()); + } + exit_after_SetParse = true; + } else { + unable_to_parse_set_statement(lock_hostgroup); + return false; + } + } else if (var == "character_set_results") { + std::string value1 = *values; + int vl = strlen(value1.c_str()); + const char *v = value1.c_str(); + bool only_normal_chars = true; + for (int i=0; imyconn->options.character_set_results_int != character_set_results_int) { + client_myds->myconn->options.character_set_results_int = character_set_results_int; + if (client_myds->myconn->options.character_set_results) { + free(client_myds->myconn->options.character_set_results); + } + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Changing connection character_set_results to %s\n", value1.c_str()); + client_myds->myconn->options.character_set_results=strdup(value1.c_str()); + } + exit_after_SetParse = true; + } else { + unable_to_parse_set_statement(lock_hostgroup); + return false; + } } else if (var == "names") { std::string value1 = *values++; std::size_t found_at = value1.find("@"); if (found_at != std::string::npos) { -#ifdef DEBUG - string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); - proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Locking hostgroup for query %s\n", nqn.c_str()); -#endif - *lock_hostgroup = true; + unable_to_parse_set_statement(lock_hostgroup); + return false; } proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET NAMES %s\n", value1.c_str()); const MARIADB_CHARSET_INFO * c; @@ -5036,22 +5728,22 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } else { proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection charset to %d\n", c->nr); client_myds->myconn->set_charset(c->nr); + exit_after_SetParse = true; } } else { std::string value1 = *values; std::size_t found_at = value1.find("@"); if (found_at != std::string::npos) { -#ifdef DEBUG - string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); - proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Locking hostgroup for query %s\n", nqn.c_str()); -#endif - *lock_hostgroup = true; + unable_to_parse_set_statement(lock_hostgroup); + return false; } } } +/* if (exit_after_SetParse) { goto __exit_set_destination_hostgroup; } +*/ // parseSetCommand wasn't able to parse anything... if (set.size() == 0) { // try case listed in #1373 @@ -5104,15 +5796,16 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } } free(v1); + if (*lock_hostgroup) { + unable_to_parse_set_statement(lock_hostgroup); + return false; + } } } } else { if (memchr((const char *)CurrentQuery.QueryPointer, '@', CurrentQuery.QueryLength)) { -#ifdef DEBUG - string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); - proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Locking hostgroup for query %s\n", nqn.c_str()); -#endif - *lock_hostgroup = true; + unable_to_parse_set_statement(lock_hostgroup); + return false; } int kq = 0; kq = strncmp((const char *)CurrentQuery.QueryPointer, (const char *)"/*!40101 SET SQL_MODE=@OLD_SQL_MODE */" , CurrentQuery.QueryLength); @@ -5127,41 +5820,73 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C } } - if (command_type == _MYSQL_COM_QUERY) { - client_myds->DSS=STATE_QUERY_SENT_NET; - uint16_t setStatus = (nTrx ? SERVER_STATUS_IN_TRANS : 0 ); - if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT; - client_myds->myprot.generate_pkt_OK(true,NULL,NULL,1,0,0,setStatus,0,NULL); + if (exit_after_SetParse) { + if (command_type == _MYSQL_COM_QUERY) { + client_myds->DSS=STATE_QUERY_SENT_NET; + uint16_t setStatus = (nTrx ? SERVER_STATUS_IN_TRANS : 0 ); + if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT; + client_myds->myprot.generate_pkt_OK(true,NULL,NULL,1,0,0,setStatus,0,NULL); client_myds->DSS=STATE_SLEEP; - status=WAITING_CLIENT_DATA; - RequestEnd(NULL); - l_free(pkt->size,pkt->ptr); - return true; + status=WAITING_CLIENT_DATA; + RequestEnd(NULL); + l_free(pkt->size,pkt->ptr); + return true; + } } - } else { - // we couldn't parse the query - string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); - if (qpo->multiplex == -1) { - // we have no rule about this SET statement. We set hostgroup locking - if (locked_on_hostgroup < 0) { - proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "SET query to cause setting lock_hostgroup: %s\n", nqn.c_str()); - if (known_query_for_locked_on_hostgroup(CurrentQuery.QueryParserArgs.digest)) { - proxy_info("Setting lock_hostgroup for SET query: %s\n", nqn.c_str()); - } else { - proxy_warning("Unable to parse unknown SET query. Setting lock_hostgroup. Please report a bug for future enhancements:%s\n", nqn.c_str()); + } else if (match_regexes && match_regexes[2]->match(dig)) { + SetParser parser(nq); + std::map> set = parser.parse2(); + for(auto it = std::begin(set); it != std::end(set); ++it) { + std::string var = it->first; + auto values = std::begin(it->second); + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET variable %s\n", var.c_str()); + if (var == "isolation level") { + std::string value1 = *values; + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET SESSION TRANSACTION ISOLATION LEVEL value %s\n", value1.c_str()); + uint32_t isolation_level_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); + if (client_myds->myconn->options.isolation_level_int != isolation_level_int) { + client_myds->myconn->options.isolation_level_int = isolation_level_int; + if (client_myds->myconn->options.isolation_level) { + free(client_myds->myconn->options.isolation_level); + } + proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection TRANSACTION ISOLATION LEVEL to %s\n", value1.c_str()); + client_myds->myconn->options.isolation_level=strdup(value1.c_str()); } - *lock_hostgroup = true; - } else { - proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "SET query to cause setting lock_hostgroup, but already set: %s\n", nqn.c_str()); - if (known_query_for_locked_on_hostgroup(CurrentQuery.QueryParserArgs.digest)) { - //proxy_info("Setting lock_hostgroup for SET query: %s\n", nqn.c_str()); - } else { - proxy_warning("Unable to parse unknown SET query. Not setting lock_hostgroup because already set. Please report a bug for future enhancements: %s\n", nqn.c_str()); + exit_after_SetParse = true; + } else if (var == "read") { + std::string value1 = *values; + proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Processing SET SESSION TRANSACTION READ value %s\n", value1.c_str()); + uint32_t transaction_read_int=SpookyHash::Hash32(value1.c_str(),value1.length(),10); + if (client_myds->myconn->options.transaction_read_int != transaction_read_int) { + client_myds->myconn->options.transaction_read_int = transaction_read_int; + if (client_myds->myconn->options.transaction_read) { + free(client_myds->myconn->options.transaction_read); + } + proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection TRANSACTION READ to %s\n", value1.c_str()); + client_myds->myconn->options.transaction_read=strdup(value1.c_str()); } + exit_after_SetParse = true; + } else { + unable_to_parse_set_statement(lock_hostgroup); + return false; + } + } + if (exit_after_SetParse) { + if (command_type == _MYSQL_COM_QUERY) { + client_myds->DSS=STATE_QUERY_SENT_NET; + uint16_t setStatus = (nTrx ? SERVER_STATUS_IN_TRANS : 0 ); + if (autocommit) setStatus |= SERVER_STATUS_AUTOCOMMIT; + client_myds->myprot.generate_pkt_OK(true,NULL,NULL,1,0,0,setStatus,0,NULL); + client_myds->DSS=STATE_SLEEP; + status=WAITING_CLIENT_DATA; + RequestEnd(NULL); + l_free(pkt->size,pkt->ptr); + return true; } - } else { - proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Unable to parse SET query but NOT setting lock_hostgroup %s\n", nqn.c_str()); } + } else { + unable_to_parse_set_statement(lock_hostgroup); + return false; } } } @@ -6115,3 +6840,32 @@ bool MySQL_Session::known_query_for_locked_on_hostgroup(uint64_t digest) { } return ret; } + + + +void MySQL_Session::unable_to_parse_set_statement(bool *lock_hostgroup) { + // we couldn't parse the query + string nqn = string((char *)CurrentQuery.QueryPointer,CurrentQuery.QueryLength); + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Locking hostgroup for query %s\n", nqn.c_str()); + if (qpo->multiplex == -1) { + // we have no rule about this SET statement. We set hostgroup locking + if (locked_on_hostgroup < 0) { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "SET query to cause setting lock_hostgroup: %s\n", nqn.c_str()); + if (known_query_for_locked_on_hostgroup(CurrentQuery.QueryParserArgs.digest)) { + proxy_info("Setting lock_hostgroup for SET query: %s\n", nqn.c_str()); + } else { + proxy_warning("Unable to parse unknown SET query. Setting lock_hostgroup. Please report a bug for future enhancements:%s\n", nqn.c_str()); + } + *lock_hostgroup = true; + } else { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "SET query to cause setting lock_hostgroup, but already set: %s\n", nqn.c_str()); + if (known_query_for_locked_on_hostgroup(CurrentQuery.QueryParserArgs.digest)) { + //proxy_info("Setting lock_hostgroup for SET query: %s\n", nqn.c_str()); + } else { + proxy_warning("Unable to parse unknown SET query. Not setting lock_hostgroup because already set. Please report a bug for future enhancements: %s\n", nqn.c_str()); + } + } + } else { + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 5, "Unable to parse SET query but NOT setting lock_hostgroup %s\n", nqn.c_str()); + } +} diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp index 6cdf254bc..0387ec80d 100644 --- a/lib/MySQL_Thread.cpp +++ b/lib/MySQL_Thread.cpp @@ -333,6 +333,16 @@ static char * mysql_thread_variables_names[]= { (char *)"add_ldap_user_comment", (char *)"default_sql_mode", (char *)"default_time_zone", + (char *)"default_isolation_level", + (char *)"default_transaction_read", + (char *)"default_character_set_results", + (char *)"default_session_track_gtids", + (char *)"default_sql_auto_is_null", + (char *)"default_sql_select_limit", + (char *)"default_sql_safe_updates", + (char *)"default_collation_connection", + (char *)"default_net_write_timeout", + (char *)"default_max_join_size", (char *)"connpoll_reset_queue_length", (char *)"min_num_servers_lantency_awareness", (char *)"stats_time_backend_query", @@ -432,6 +442,16 @@ MySQL_Threads_Handler::MySQL_Threads_Handler() { variables.add_ldap_user_comment=NULL; variables.default_sql_mode=strdup((char *)MYSQL_DEFAULT_SQL_MODE); variables.default_time_zone=strdup((char *)MYSQL_DEFAULT_TIME_ZONE); + variables.default_isolation_level=strdup((char *)MYSQL_DEFAULT_ISOLATION_LEVEL); + variables.default_transaction_read=strdup((char *)MYSQL_DEFAULT_TRANSACTION_READ); + variables.default_character_set_results=strdup((char *)MYSQL_DEFAULT_CHARACTER_SET_RESULTS); + variables.default_session_track_gtids=strdup((char *)MYSQL_DEFAULT_SESSION_TRACK_GTIDS); + variables.default_sql_auto_is_null=strdup((char *)MYSQL_DEFAULT_SQL_AUTO_IS_NULL); + variables.default_sql_select_limit=strdup((char *)MYSQL_DEFAULT_SQL_SELECT_LIMIT); + variables.default_sql_safe_updates=strdup((char *)MYSQL_DEFAULT_SQL_SAFE_UPDATES); + variables.default_collation_connection=strdup((char *)MYSQL_DEFAULT_COLLATION_CONNECTION); + variables.default_net_write_timeout=strdup((char *)MYSQL_DEFAULT_NET_WRITE_TIMEOUT); + variables.default_max_join_size=strdup((char *)MYSQL_DEFAULT_MAX_JOIN_SIZE); variables.ping_interval_server_msec=10000; variables.ping_timeout_server=200; variables.default_schema=strdup((char *)"information_schema"); @@ -634,6 +654,66 @@ char * MySQL_Threads_Handler::get_variable_string(char *name) { } return strdup(variables.default_time_zone); } + if (!strcmp(name,"default_isolation_level")) { + if (variables.default_isolation_level==NULL) { + variables.default_isolation_level=strdup((char *)MYSQL_DEFAULT_ISOLATION_LEVEL); + } + return strdup(variables.default_isolation_level); + } + if (!strcmp(name,"default_transaction_read")) { + if (variables.default_transaction_read==NULL) { + variables.default_transaction_read=strdup((char *)MYSQL_DEFAULT_TRANSACTION_READ); + } + return strdup(variables.default_transaction_read); + } + if (!strcmp(name,"default_character_set_results")) { + if (variables.default_character_set_results==NULL) { + variables.default_character_set_results=strdup((char *)MYSQL_DEFAULT_CHARACTER_SET_RESULTS); + } + return strdup(variables.default_character_set_results); + } + if (!strcmp(name,"default_session_track_gtids")) { + if (variables.default_session_track_gtids==NULL) { + variables.default_session_track_gtids=strdup((char *)MYSQL_DEFAULT_SESSION_TRACK_GTIDS); + } + return strdup(variables.default_session_track_gtids); + } + if (!strcmp(name,"default_sql_auto_is_null")) { + if (variables.default_sql_auto_is_null==NULL) { + variables.default_sql_auto_is_null=strdup((char *)MYSQL_DEFAULT_SQL_AUTO_IS_NULL); + } + return strdup(variables.default_sql_auto_is_null); + } + if (!strcmp(name,"default_sql_select_limit")) { + if (variables.default_sql_select_limit==NULL) { + variables.default_sql_select_limit=strdup((char *)MYSQL_DEFAULT_SQL_SELECT_LIMIT); + } + return strdup(variables.default_sql_select_limit); + } + if (!strcmp(name,"default_sql_safe_updates")) { + if (variables.default_sql_safe_updates==NULL) { + variables.default_sql_safe_updates=strdup((char *)MYSQL_DEFAULT_SQL_SAFE_UPDATES); + } + return strdup(variables.default_sql_safe_updates); + } + if (!strcmp(name,"default_collation_connection")) { + if (variables.default_collation_connection==NULL) { + variables.default_collation_connection=strdup((char *)MYSQL_DEFAULT_COLLATION_CONNECTION); + } + return strdup(variables.default_collation_connection); + } + if (!strcmp(name,"default_net_write_timeout")) { + if (variables.default_net_write_timeout==NULL) { + variables.default_net_write_timeout=strdup((char *)MYSQL_DEFAULT_NET_WRITE_TIMEOUT); + } + return strdup(variables.default_net_write_timeout); + } + if (!strcmp(name,"default_max_join_size")) { + if (variables.default_max_join_size==NULL) { + variables.default_max_join_size=strdup((char *)MYSQL_DEFAULT_MAX_JOIN_SIZE); + } + return strdup(variables.default_max_join_size); + } if (!strcmp(name,"server_version")) return strdup(variables.server_version); if (!strcmp(name,"eventslog_filename")) return strdup(variables.eventslog_filename); if (!strcmp(name,"auditlog_filename")) return strdup(variables.auditlog_filename); @@ -873,6 +953,66 @@ char * MySQL_Threads_Handler::get_variable(char *name) { // this is the public f } return strdup(variables.default_time_zone); } + if (!strcasecmp(name,"default_isolation_level")) { + if (variables.default_isolation_level==NULL) { + variables.default_isolation_level=strdup((char *)MYSQL_DEFAULT_ISOLATION_LEVEL); + } + return strdup(variables.default_isolation_level); + } + if (!strcasecmp(name,"default_transaction_read")) { + if (variables.default_transaction_read==NULL) { + variables.default_transaction_read=strdup((char *)MYSQL_DEFAULT_TRANSACTION_READ); + } + return strdup(variables.default_transaction_read); + } + if (!strcasecmp(name,"default_character_set_results")) { + if (variables.default_character_set_results==NULL) { + variables.default_character_set_results=strdup((char *)MYSQL_DEFAULT_CHARACTER_SET_RESULTS); + } + return strdup(variables.default_character_set_results); + } + if (!strcasecmp(name,"default_session_track_gtids")) { + if (variables.default_session_track_gtids==NULL) { + variables.default_session_track_gtids=strdup((char *)MYSQL_DEFAULT_SESSION_TRACK_GTIDS); + } + return strdup(variables.default_session_track_gtids); + } + if (!strcasecmp(name,"default_sql_auto_is_null")) { + if (variables.default_sql_auto_is_null==NULL) { + variables.default_sql_auto_is_null=strdup((char *)MYSQL_DEFAULT_SQL_AUTO_IS_NULL); + } + return strdup(variables.default_sql_auto_is_null); + } + if (!strcasecmp(name,"default_sql_select_limit")) { + if (variables.default_sql_select_limit==NULL) { + variables.default_sql_select_limit=strdup((char *)MYSQL_DEFAULT_SQL_SELECT_LIMIT); + } + return strdup(variables.default_sql_select_limit); + } + if (!strcasecmp(name,"default_sql_safe_updates")) { + if (variables.default_sql_safe_updates==NULL) { + variables.default_sql_safe_updates=strdup((char *)MYSQL_DEFAULT_SQL_SAFE_UPDATES); + } + return strdup(variables.default_sql_safe_updates); + } + if (!strcasecmp(name,"default_collation_connection")) { + if (variables.default_collation_connection==NULL) { + variables.default_collation_connection=strdup((char *)MYSQL_DEFAULT_COLLATION_CONNECTION); + } + return strdup(variables.default_collation_connection); + } + if (!strcasecmp(name,"default_net_write_timeout")) { + if (variables.default_net_write_timeout==NULL) { + variables.default_net_write_timeout=strdup((char *)MYSQL_DEFAULT_NET_WRITE_TIMEOUT); + } + return strdup(variables.default_net_write_timeout); + } + if (!strcasecmp(name,"default_max_join_size")) { + if (variables.default_max_join_size==NULL) { + variables.default_max_join_size=strdup((char *)MYSQL_DEFAULT_MAX_JOIN_SIZE); + } + return strdup(variables.default_max_join_size); + } if (!strcasecmp(name,"server_version")) return strdup(variables.server_version); if (!strcasecmp(name,"auditlog_filename")) return strdup(variables.auditlog_filename); if (!strcasecmp(name,"eventslog_filename")) return strdup(variables.eventslog_filename); @@ -2139,6 +2279,136 @@ bool MySQL_Threads_Handler::set_variable(char *name, char *value) { // this is t return true; } + if (!strcasecmp(name,"default_isolation_level")) { + if (variables.default_isolation_level) free(variables.default_isolation_level); + variables.default_isolation_level=NULL; + if (vallen) { + if (strcmp(value,"(null)")) + variables.default_isolation_level=strdup(value); + } + if (variables.default_isolation_level==NULL) { + variables.default_isolation_level=strdup((char *)MYSQL_DEFAULT_ISOLATION_LEVEL); // default + } + return true; + } + + if (!strcasecmp(name,"default_transaction_read")) { + if (variables.default_transaction_read) free(variables.default_transaction_read); + variables.default_transaction_read=NULL; + if (vallen) { + if (strcmp(value,"(null)")) + variables.default_transaction_read=strdup(value); + } + if (variables.default_transaction_read==NULL) { + variables.default_transaction_read=strdup((char *)MYSQL_DEFAULT_TRANSACTION_READ); // default + } + return true; + } + + if (!strcasecmp(name,"default_character_set_results")) { + if (variables.default_character_set_results) free(variables.default_character_set_results); + variables.default_character_set_results=NULL; + if (vallen) { + if (strcmp(value,"(null)")) + variables.default_character_set_results=strdup(value); + } + if (variables.default_character_set_results==NULL) { + variables.default_character_set_results=strdup((char *)MYSQL_DEFAULT_CHARACTER_SET_RESULTS); // default + } + return true; + } + + if (!strcasecmp(name,"default_session_track_gtids")) { + if (variables.default_session_track_gtids) free(variables.default_session_track_gtids); + variables.default_session_track_gtids=NULL; + if (vallen) { + if (strcmp(value,"(null)")) + variables.default_session_track_gtids=strdup(value); + } + if (variables.default_session_track_gtids==NULL) { + variables.default_session_track_gtids=strdup((char *)MYSQL_DEFAULT_SESSION_TRACK_GTIDS); // default + } + return true; + } + + if (!strcasecmp(name,"default_sql_auto_is_null")) { + if (variables.default_sql_auto_is_null) free(variables.default_sql_auto_is_null); + variables.default_sql_auto_is_null=NULL; + if (vallen) { + if (strcmp(value,"(null)")) + variables.default_sql_auto_is_null=strdup(value); + } + if (variables.default_sql_auto_is_null==NULL) { + variables.default_sql_auto_is_null=strdup((char *)MYSQL_DEFAULT_SQL_AUTO_IS_NULL); // default + } + return true; + } + + if (!strcasecmp(name,"default_sql_select_limit")) { + if (variables.default_sql_select_limit) free(variables.default_sql_select_limit); + variables.default_sql_select_limit=NULL; + if (vallen) { + if (strcmp(value,"(null)")) + variables.default_sql_select_limit=strdup(value); + } + if (variables.default_sql_select_limit==NULL) { + variables.default_sql_select_limit=strdup((char *)MYSQL_DEFAULT_SQL_SELECT_LIMIT); // default + } + return true; + } + + if (!strcasecmp(name,"default_sql_safe_updates")) { + if (variables.default_sql_safe_updates) free(variables.default_sql_safe_updates); + variables.default_sql_safe_updates=NULL; + if (vallen) { + if (strcmp(value,"(null)")) + variables.default_sql_safe_updates=strdup(value); + } + if (variables.default_sql_safe_updates==NULL) { + variables.default_sql_safe_updates=strdup((char *)MYSQL_DEFAULT_SQL_SAFE_UPDATES); // default + } + return true; + } + + if (!strcasecmp(name,"default_collation_connection")) { + if (variables.default_collation_connection) free(variables.default_collation_connection); + variables.default_collation_connection=NULL; + if (vallen) { + if (strcmp(value,"(null)")) + variables.default_collation_connection=strdup(value); + } + if (variables.default_collation_connection==NULL) { + variables.default_collation_connection=strdup((char *)MYSQL_DEFAULT_COLLATION_CONNECTION); // default + } + return true; + } + + if (!strcasecmp(name,"default_net_write_timeout")) { + if (variables.default_net_write_timeout) free(variables.default_net_write_timeout); + variables.default_net_write_timeout=NULL; + if (vallen) { + if (strcmp(value,"(null)")) + variables.default_net_write_timeout=strdup(value); + } + if (variables.default_net_write_timeout==NULL) { + variables.default_net_write_timeout=strdup((char *)MYSQL_DEFAULT_NET_WRITE_TIMEOUT); // default + } + return true; + } + + if (!strcasecmp(name,"default_max_join_size")) { + if (variables.default_max_join_size) free(variables.default_max_join_size); + variables.default_max_join_size=NULL; + if (vallen) { + if (strcmp(value,"(null)")) + variables.default_max_join_size=strdup(value); + } + if (variables.default_max_join_size==NULL) { + variables.default_max_join_size=strdup((char *)MYSQL_DEFAULT_MAX_JOIN_SIZE); // default + } + return true; + } + if (!strcasecmp(name,"keep_multiplexing_variables")) { if (vallen) { free(variables.keep_multiplexing_variables); @@ -2749,6 +3019,16 @@ MySQL_Threads_Handler::~MySQL_Threads_Handler() { if (variables.add_ldap_user_comment) free(variables.add_ldap_user_comment); if (variables.default_sql_mode) free(variables.default_sql_mode); if (variables.default_time_zone) free(variables.default_time_zone); + if (variables.default_isolation_level) free(variables.default_isolation_level); + if (variables.default_transaction_read) free(variables.default_transaction_read); + if (variables.default_character_set_results) free(variables.default_character_set_results); + if (variables.default_session_track_gtids) free(variables.default_session_track_gtids); + if (variables.default_sql_auto_is_null) free(variables.default_sql_auto_is_null); + if (variables.default_sql_select_limit) free(variables.default_sql_select_limit); + if (variables.default_sql_safe_updates) free(variables.default_sql_safe_updates); + if (variables.default_collation_connection) free(variables.default_collation_connection); + if (variables.default_net_write_timeout) free(variables.default_net_write_timeout); + if (variables.default_max_join_size) free(variables.default_max_join_size); if (variables.eventslog_filename) free(variables.eventslog_filename); if (variables.auditlog_filename) free(variables.auditlog_filename); if (variables.ssl_p2s_ca) free(variables.ssl_p2s_ca); @@ -2869,6 +3149,16 @@ MySQL_Thread::~MySQL_Thread() { if (mysql_thread___add_ldap_user_comment) { free(mysql_thread___add_ldap_user_comment); mysql_thread___add_ldap_user_comment=NULL; } if (mysql_thread___default_sql_mode) { free(mysql_thread___default_sql_mode); mysql_thread___default_sql_mode=NULL; } if (mysql_thread___default_time_zone) { free(mysql_thread___default_time_zone); mysql_thread___default_time_zone=NULL; } + if (mysql_thread___default_isolation_level) { free(mysql_thread___default_isolation_level); mysql_thread___default_isolation_level=NULL; } + if (mysql_thread___default_transaction_read) { free(mysql_thread___default_transaction_read); mysql_thread___default_transaction_read=NULL; } + if (mysql_thread___default_character_set_results) { free(mysql_thread___default_character_set_results); mysql_thread___default_character_set_results=NULL; } + if (mysql_thread___default_session_track_gtids) { free(mysql_thread___default_session_track_gtids); mysql_thread___default_session_track_gtids=NULL; } + if (mysql_thread___default_sql_auto_is_null) { free(mysql_thread___default_sql_auto_is_null); mysql_thread___default_sql_auto_is_null=NULL; } + if (mysql_thread___default_sql_select_limit) { free(mysql_thread___default_sql_select_limit); mysql_thread___default_sql_select_limit=NULL; } + if (mysql_thread___default_sql_safe_updates) { free(mysql_thread___default_sql_safe_updates); mysql_thread___default_sql_safe_updates=NULL; } + if (mysql_thread___default_collation_connection) { free(mysql_thread___default_collation_connection); mysql_thread___default_collation_connection=NULL; } + if (mysql_thread___default_net_write_timeout) { free(mysql_thread___default_net_write_timeout); mysql_thread___default_net_write_timeout=NULL; } + if (mysql_thread___default_max_join_size) { free(mysql_thread___default_max_join_size); mysql_thread___default_max_join_size=NULL; } if (mysql_thread___eventslog_filename) { free(mysql_thread___eventslog_filename); mysql_thread___eventslog_filename=NULL; } if (mysql_thread___auditlog_filename) { free(mysql_thread___auditlog_filename); mysql_thread___auditlog_filename=NULL; } if (mysql_thread___ssl_p2s_ca) { free(mysql_thread___ssl_p2s_ca); mysql_thread___ssl_p2s_ca=NULL; } @@ -2931,6 +3221,77 @@ MySQL_Session * MySQL_Thread::create_new_session_and_client_data_stream(int _fd) free(sess->client_myds->myconn->options.time_zone); } sess->client_myds->myconn->options.time_zone=strdup(mysql_thread___default_time_zone); + + uint32_t isolation_level_int=SpookyHash::Hash32(mysql_thread___default_isolation_level,strlen(mysql_thread___default_isolation_level),10); + sess->client_myds->myconn->options.isolation_level_int = isolation_level_int; + if (sess->client_myds->myconn->options.isolation_level) { + free(sess->client_myds->myconn->options.isolation_level); + } + sess->client_myds->myconn->options.isolation_level=strdup(mysql_thread___default_isolation_level); + + uint32_t transaction_read_int=SpookyHash::Hash32(mysql_thread___default_transaction_read,strlen(mysql_thread___default_transaction_read),10); + sess->client_myds->myconn->options.transaction_read_int = transaction_read_int; + if (sess->client_myds->myconn->options.transaction_read) { + free(sess->client_myds->myconn->options.transaction_read); + } + sess->client_myds->myconn->options.transaction_read=strdup(mysql_thread___default_transaction_read); + + uint32_t character_set_results_int=SpookyHash::Hash32(mysql_thread___default_character_set_results,strlen(mysql_thread___default_character_set_results),10); + sess->client_myds->myconn->options.character_set_results_int = character_set_results_int; + if (sess->client_myds->myconn->options.character_set_results) { + free(sess->client_myds->myconn->options.character_set_results); + } + sess->client_myds->myconn->options.character_set_results=strdup(mysql_thread___default_character_set_results); + + uint32_t session_track_gtids_int=SpookyHash::Hash32(mysql_thread___default_session_track_gtids,strlen(mysql_thread___default_session_track_gtids),10); + sess->client_myds->myconn->options.session_track_gtids_int = session_track_gtids_int; + if (sess->client_myds->myconn->options.session_track_gtids) { + free(sess->client_myds->myconn->options.session_track_gtids); + } + sess->client_myds->myconn->options.session_track_gtids=strdup(mysql_thread___default_session_track_gtids); + + uint32_t sql_auto_is_null_int=SpookyHash::Hash32(mysql_thread___default_sql_auto_is_null,strlen(mysql_thread___default_sql_auto_is_null),10); + sess->client_myds->myconn->options.sql_auto_is_null_int = sql_auto_is_null_int; + if (sess->client_myds->myconn->options.sql_auto_is_null) { + free(sess->client_myds->myconn->options.sql_auto_is_null); + } + sess->client_myds->myconn->options.sql_auto_is_null=strdup(mysql_thread___default_sql_auto_is_null); + + uint32_t sql_select_limit_int=SpookyHash::Hash32(mysql_thread___default_sql_select_limit,strlen(mysql_thread___default_sql_select_limit),10); + sess->client_myds->myconn->options.sql_select_limit_int = sql_select_limit_int; + if (sess->client_myds->myconn->options.sql_select_limit) { + free(sess->client_myds->myconn->options.sql_select_limit); + } + sess->client_myds->myconn->options.sql_select_limit=strdup(mysql_thread___default_sql_select_limit); + + uint32_t sql_safe_updates_int=SpookyHash::Hash32(mysql_thread___default_sql_safe_updates,strlen(mysql_thread___default_sql_safe_updates),10); + sess->client_myds->myconn->options.sql_safe_updates_int = sql_safe_updates_int; + if (sess->client_myds->myconn->options.sql_safe_updates) { + free(sess->client_myds->myconn->options.sql_safe_updates); + } + sess->client_myds->myconn->options.sql_safe_updates=strdup(mysql_thread___default_sql_safe_updates); + + uint32_t collation_connection_int=SpookyHash::Hash32(mysql_thread___default_collation_connection,strlen(mysql_thread___default_collation_connection),10); + sess->client_myds->myconn->options.collation_connection_int = collation_connection_int; + if (sess->client_myds->myconn->options.collation_connection) { + free(sess->client_myds->myconn->options.collation_connection); + } + sess->client_myds->myconn->options.collation_connection=strdup(mysql_thread___default_collation_connection); + + uint32_t net_write_timeout_int=SpookyHash::Hash32(mysql_thread___default_net_write_timeout,strlen(mysql_thread___default_net_write_timeout),10); + sess->client_myds->myconn->options.net_write_timeout_int = net_write_timeout_int; + if (sess->client_myds->myconn->options.net_write_timeout) { + free(sess->client_myds->myconn->options.net_write_timeout); + } + sess->client_myds->myconn->options.net_write_timeout=strdup(mysql_thread___default_net_write_timeout); + + uint32_t max_join_size_int=SpookyHash::Hash32(mysql_thread___default_max_join_size,strlen(mysql_thread___default_max_join_size),10); + sess->client_myds->myconn->options.max_join_size_int = max_join_size_int; + if (sess->client_myds->myconn->options.max_join_size) { + free(sess->client_myds->myconn->options.max_join_size); + } + sess->client_myds->myconn->options.max_join_size=strdup(mysql_thread___default_max_join_size); + return sess; } @@ -2969,8 +3330,8 @@ bool MySQL_Thread::init() { match_regexes=(Session_Regex **)malloc(sizeof(Session_Regex *)*3); match_regexes[0]=new Session_Regex((char *)"^SET (|SESSION |@@|@@session.)SQL_LOG_BIN( *)(:|)=( *)"); - match_regexes[1]=new Session_Regex((char *)"^SET (|SESSION |@@|@@session.)SQL_MODE( *)(:|)=( *)"); - match_regexes[2]=new Session_Regex((char *)"^SET (|SESSION |@@|@@session.)TIME_ZONE( *)(:|)=( *)"); + match_regexes[1]=new Session_Regex((char *)"^SET (|SESSION |@@|@@session.)(SQL_MODE|TIME_ZONE|CHARACTER_SET_RESULTS|SESSION_TRACK_GTIDS|SQL_AUTO_IS_NULL|SQL_SELECT_LIMIT|SQL_SAFE_UPDATES|COLLATION_CONNECTION|NET_WRITE_TIMEOUT|MAX_JOIN_SIZE( *)(:|)=( *))"); + match_regexes[2]=new Session_Regex((char *)"^SET(?: +)(|SESSION +)TRANSACTION(?: +)(?:(?:(ISOLATION(?: +)LEVEL)(?: +)(REPEATABLE(?: +)READ|READ(?: +)COMMITTED|READ(?: +)UNCOMMITTED|SERIALIZABLE))|(?:(READ)(?: +)(WRITE|ONLY)))"); return true; @@ -3996,6 +4357,26 @@ void MySQL_Thread::refresh_variables() { mysql_thread___default_sql_mode=GloMTH->get_variable_string((char *)"default_sql_mode"); if (mysql_thread___default_time_zone) free(mysql_thread___default_time_zone); mysql_thread___default_time_zone=GloMTH->get_variable_string((char *)"default_time_zone"); + if (mysql_thread___default_isolation_level) free(mysql_thread___default_isolation_level); + mysql_thread___default_isolation_level=GloMTH->get_variable_string((char *)"default_isolation_level"); + if (mysql_thread___default_transaction_read) free(mysql_thread___default_transaction_read); + mysql_thread___default_transaction_read=GloMTH->get_variable_string((char *)"default_transaction_read"); + if (mysql_thread___default_character_set_results) free(mysql_thread___default_character_set_results); + mysql_thread___default_character_set_results=GloMTH->get_variable_string((char *)"default_character_set_results"); + if (mysql_thread___default_session_track_gtids) free(mysql_thread___default_session_track_gtids); + mysql_thread___default_session_track_gtids=GloMTH->get_variable_string((char *)"default_session_track_gtids"); + if (mysql_thread___default_sql_auto_is_null) free(mysql_thread___default_sql_auto_is_null); + mysql_thread___default_sql_auto_is_null=GloMTH->get_variable_string((char *)"default_sql_auto_is_null"); + if (mysql_thread___default_sql_select_limit) free(mysql_thread___default_sql_select_limit); + mysql_thread___default_sql_select_limit=GloMTH->get_variable_string((char *)"default_sql_select_limit"); + if (mysql_thread___default_sql_safe_updates) free(mysql_thread___default_sql_safe_updates); + mysql_thread___default_sql_safe_updates=GloMTH->get_variable_string((char *)"default_sql_safe_updates"); + if (mysql_thread___default_collation_connection) free(mysql_thread___default_collation_connection); + mysql_thread___default_collation_connection=GloMTH->get_variable_string((char *)"default_collation_connection"); + if (mysql_thread___default_net_write_timeout) free(mysql_thread___default_net_write_timeout); + mysql_thread___default_net_write_timeout=GloMTH->get_variable_string((char *)"default_net_write_timeout"); + if (mysql_thread___default_max_join_size) free(mysql_thread___default_max_join_size); + mysql_thread___default_max_join_size=GloMTH->get_variable_string((char *)"default_max_join_size"); if (mysql_thread___server_version) free(mysql_thread___server_version); mysql_thread___server_version=GloMTH->get_variable_string((char *)"server_version"); if (mysql_thread___eventslog_filename) free(mysql_thread___eventslog_filename); diff --git a/lib/configfile.cpp b/lib/configfile.cpp index b09e62f1c..9565896f4 100644 --- a/lib/configfile.cpp +++ b/lib/configfile.cpp @@ -67,7 +67,11 @@ bool ProxySQL_ConfigFile::OpenFile(const char *__filename) { }; void ProxySQL_ConfigFile::CloseFile() { - delete cfg; +/* FIXME + for now we are commenting out this. + It seems that after upgrade to jemalloc 5.2.0 , valgrind crashes here +*/ +// delete cfg; cfg=NULL; } diff --git a/lib/mysql_connection.cpp b/lib/mysql_connection.cpp index eb62c83bb..683f781ae 100644 --- a/lib/mysql_connection.cpp +++ b/lib/mysql_connection.cpp @@ -28,9 +28,9 @@ static char * session_vars[]= { // For issue #555 , multiplexing is disabled if --safe-updates is used //(char *)"SQL_SAFE_UPDATES=?,SQL_SELECT_LIMIT=?,MAX_JOIN_SIZE=?", // for issue #1832 , we are splitting the above into 3 variables - (char *)"SQL_SAFE_UPDATES", - (char *)"SQL_SELECT_LIMIT", - (char *)"MAX_JOIN_SIZE", +// (char *)"SQL_SAFE_UPDATES", +// (char *)"SQL_SELECT_LIMIT", +// (char *)"MAX_JOIN_SIZE", (char *)"FOREIGN_KEY_CHECKS", (char *)"UNIQUE_CHECKS", (char *)"AUTO_INCREMENT_INCREMENT", @@ -206,6 +206,26 @@ MySQL_Connection::MySQL_Connection() { options.no_backslash_escapes=false; options.init_connect=NULL; options.init_connect_sent=false; + options.character_set_results = NULL; + options.isolation_level = NULL; + options.transaction_read = NULL; + options.session_track_gtids = NULL; + options.sql_auto_is_null = NULL; + options.sql_select_limit = NULL; + options.sql_safe_updates = NULL; + options.collation_connection = NULL; + options.net_write_timeout = NULL; + options.max_join_size = NULL; + options.isolation_level_sent = false; + options.transaction_read_sent = false; + options.character_set_results_sent = false; + options.session_track_gtids_sent = false; + options.sql_auto_is_null_sent = false; + options.sql_select_limit_sent = false; + options.sql_safe_updates_sent = false; + options.collation_connection_sent = false; + options.net_write_timeout_sent = false; + options.max_join_size_sent = false; options.sql_mode_sent=false; options.ldap_user_variable=NULL; options.ldap_user_variable_value=NULL; @@ -215,6 +235,16 @@ MySQL_Connection::MySQL_Connection() { options.sql_mode_int=0; // #509 options.time_zone=NULL; // #819 options.time_zone_int=0; // #819 + options.isolation_level_int=0; + options.transaction_read_int=0; + options.character_set_results_int=0; + options.session_track_gtids_int=0; + options.sql_auto_is_null_int=0; + options.sql_select_limit_int=0; + options.sql_safe_updates_int=0; + options.collation_connection_int=0; + options.net_write_timeout_int=0; + options.max_join_size_int=0; compression_pkt_id=0; mysql_result=NULL; query.ptr=NULL; @@ -291,6 +321,46 @@ MySQL_Connection::~MySQL_Connection() { free(options.time_zone); options.time_zone=NULL; } + if (options.isolation_level) { + free(options.isolation_level); + options.isolation_level=NULL; + } + if (options.transaction_read) { + free(options.transaction_read); + options.transaction_read=NULL; + } + if (options.character_set_results) { + free(options.character_set_results); + options.character_set_results=NULL; + } + if (options.session_track_gtids) { + free(options.session_track_gtids); + options.session_track_gtids=NULL; + } + if (options.sql_auto_is_null) { + free(options.sql_auto_is_null); + options.sql_auto_is_null=NULL; + } + if (options.sql_select_limit) { + free(options.sql_select_limit); + options.sql_select_limit=NULL; + } + if (options.sql_safe_updates) { + free(options.sql_safe_updates); + options.sql_safe_updates=NULL; + } + if (options.collation_connection) { + free(options.collation_connection); + options.collation_connection=NULL; + } + if (options.net_write_timeout) { + free(options.net_write_timeout); + options.net_write_timeout=NULL; + } + if (options.max_join_size) { + free(options.max_join_size); + options.max_join_size=NULL; + } }; bool MySQL_Connection::set_autocommit(bool _ac) { @@ -1997,6 +2067,66 @@ void MySQL_Connection::reset() { delete local_stmts; local_stmts=new MySQL_STMTs_local_v14(false); creation_time = monotonic_time(); + options.isolation_level_int = 0; + if (options.isolation_level) { + free (options.isolation_level); + options.isolation_level = NULL; + options.isolation_level_sent = false; + } + options.transaction_read_int = 0; + if (options.transaction_read) { + free (options.transaction_read); + options.transaction_read = NULL; + options.transaction_read_sent = false; + } + options.character_set_results_int = 0; + if (options.character_set_results) { + free (options.character_set_results); + options.character_set_results = NULL; + options.character_set_results_sent = false; + } + options.session_track_gtids_int = 0; + if (options.session_track_gtids) { + free (options.session_track_gtids); + options.session_track_gtids = NULL; + options.session_track_gtids_sent = false; + } + options.sql_auto_is_null_int = 0; + if (options.sql_auto_is_null) { + free (options.sql_auto_is_null); + options.sql_auto_is_null = NULL; + options.sql_auto_is_null_sent = false; + } + options.sql_select_limit_int = 0; + if (options.sql_select_limit) { + free (options.sql_select_limit); + options.sql_select_limit = NULL; + options.sql_select_limit_sent = false; + } + options.sql_safe_updates_int = 0; + if (options.sql_safe_updates) { + free (options.sql_safe_updates); + options.sql_safe_updates = NULL; + options.sql_safe_updates_sent = false; + } + options.collation_connection_int = 0; + if (options.collation_connection) { + free (options.collation_connection); + options.collation_connection = NULL; + options.collation_connection_sent = false; + } + options.net_write_timeout_int = 0; + if (options.net_write_timeout) { + free (options.net_write_timeout); + options.net_write_timeout = NULL; + options.net_write_timeout_sent = false; + } + options.max_join_size_int = 0; + if (options.max_join_size) { + free (options.max_join_size); + options.max_join_size = NULL; + options.max_join_size_sent = false; + } if (options.init_connect) { free(options.init_connect); options.init_connect = NULL; diff --git a/lib/set_parser.cpp b/lib/set_parser.cpp index 640f7bd5b..b46fb32df 100644 --- a/lib/set_parser.cpp +++ b/lib/set_parser.cpp @@ -16,7 +16,12 @@ SetParser::SetParser(std::string nq) { free(query_no_space); } -std::map> SetParser::parse() { +#define QUOTES "(?:'|\")?" +#define SPACES " *" +#define NAMES "(NAMES)" +#define NAME_VALUE "((?:\\w|\\d)+)" + +std::map> SetParser::parse1() { proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "Parsing query %s\n", query.c_str()); re2::RE2::Options *opt2=new re2::RE2::Options(RE2::Quiet); @@ -28,17 +33,13 @@ std::map> SetParser::parse() { std::map> result; -#define NAMES "(NAMES)" -#define QUOTES "(?:'|\")?" -#define NAME_VALUE "((?:\\w|\\d)+)" -#define SESSION "(?:|SESSION +|@@|@@session.)" -#define VAR "(\\w+)" -#define SPACES " *" +#define SESSION_P1 "(?:|SESSION +|@@|@@session.)" +#define VAR_P1 "(\\w+)" //#define VAR_VALUE "((?:[\\w/\\d:\\+\\-]|,)+)" //#define VAR_VALUE "((?:CONCAT\\((?:(REPLACE|CONCAT)\\()+@@sql_mode,(?:(?:'|\\w|,| |\"|\\))+(?:\\)))|(?:[@\\w/\\d:\\+\\-]|,)+|(?:)))" -#define VAR_VALUE "(((?:CONCAT\\()*(?:((?: )*REPLACE|IFNULL|CONCAT)\\()+(?: )*(?:NULL|@OLD_SQL_MODE|@@sql_mode),(?:(?:'|\\w|,| |\"|\\))+(?:\\))*)|(?:[@\\w/\\d:\\+\\-]|,)+|(?:)))" +#define VAR_VALUE_P1 "(((?:CONCAT\\()*(?:((?: )*REPLACE|IFNULL|CONCAT)\\()+(?: )*(?:NULL|@OLD_SQL_MODE|@@sql_mode),(?:(?:'|\\w|,| |\"|\\))+(?:\\))*)|(?:[@\\w/\\d:\\+\\-]|,)+|(?:)))" - const string pattern="(?:" NAMES SPACES QUOTES NAME_VALUE QUOTES "(?: +COLLATE +" QUOTES NAME_VALUE QUOTES "|)" "|" SESSION VAR SPACES "(?:|:)=" SPACES QUOTES VAR_VALUE QUOTES ") *,? *"; + const string pattern="(?:" NAMES SPACES QUOTES NAME_VALUE QUOTES "(?: +COLLATE +" QUOTES NAME_VALUE QUOTES "|)" "|" SESSION_P1 VAR_P1 SPACES "(?:|:)=" SPACES QUOTES VAR_VALUE_P1 QUOTES ") *,? *"; re2::RE2 re(pattern, *opt2); string var; string value1, value2, value3, value4, value5; @@ -54,7 +55,7 @@ std::map> SetParser::parse() { key = value1; op.push_back(value2); if (value3 != "") { - op.push_back(value3); + op.push_back(value3); } } else if (value4 != "") { // VARIABLE @@ -70,4 +71,53 @@ std::map> SetParser::parse() { } +std::map> SetParser::parse2() { + + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "Parsing query %s\n", query.c_str()); + re2::RE2::Options *opt2=new re2::RE2::Options(RE2::Quiet); + opt2->set_case_sensitive(false); + opt2->set_longest_match(false); + + re2::RE2 re0("^\\s*SET\\s+", *opt2); + re2::RE2::Replace(&query, re0, ""); + + std::map> result; + +// regex used: +// SET(?: +)(|SESSION +)TRANSACTION(?: +)(?:(?:(ISOLATION(?: +)LEVEL)(?: +)(REPEATABLE(?: +)READ|READ(?: +)COMMITTED|READ(?: +)UNCOMMITTED|SERIALIZABLE))|(?:(READ)(?: +)(WRITE|ONLY))) +/* +#define SESSION_P2 "(|SESSION)" +#define VAR_P2 "(ISOLATION LEVEL|READ)" +//#define VAR_VALUE "((?:[\\w/\\d:\\+\\-]|,)+)" +//#define VAR_VALUE "((?:CONCAT\\((?:(REPLACE|CONCAT)\\()+@@sql_mode,(?:(?:'|\\w|,| |\"|\\))+(?:\\)))|(?:[@\\w/\\d:\\+\\-]|,)+|(?:)))" +#define VAR_VALUE_P2 "(((?:CONCAT\\()*(?:((?: )*REPLACE|IFNULL|CONCAT)\\()+(?: )*(?:NULL|@OLD_SQL_MODE|@@sql_mode),(?:(?:'|\\w|,| |\"|\\))+(?:\\))*)|(?:[@\\w/\\d:\\+\\-]|,)+|(?:)))" +*/ + //const string pattern="(?:" NAMES SPACES QUOTES NAME_VALUE QUOTES "(?: +COLLATE +" QUOTES NAME_VALUE QUOTES "|)" "|" SESSION_P1 VAR_P1 SPACES "(?:|:)=" SPACES QUOTES VAR_VALUE_P1 QUOTES ") *,? *"; + const string pattern="(|SESSION) *TRANSACTION(?: +)(?:(?:(ISOLATION(?: +)LEVEL)(?: +)(REPEATABLE(?: +)READ|READ(?: +)COMMITTED|READ(?: +)UNCOMMITTED|SERIALIZABLE))|(?:(READ)(?: +)(WRITE|ONLY)))"; + re2::RE2 re(pattern, *opt2); + string var; + string value1, value2, value3, value4, value5; + re2::StringPiece input(query); + while (re2::RE2::Consume(&input, re, &value1, &value2, &value3, &value4, &value5)) { + std::vector op; +#ifdef DEBUG + proxy_debug(PROXY_DEBUG_MYSQL_QUERY_PROCESSOR, 4, "SET parsing: v1='%s' , v2='%s' , v3='%s' , v4='%s' , v5='%s'\n", value1.c_str(), value2.c_str(), value3.c_str(), value4.c_str(), value5.c_str()); +#endif // DEBUG + string key; + if (value1 != "") { // session is specified + if (value2 != "") { // isolation level + key = value2; + std::transform(value3.begin(), value3.end(), value3.begin(), ::tolower); + op.push_back(value3); + } else { + key = value4; + std::transform(value5.begin(), value5.end(), value5.begin(), ::tolower); + op.push_back(value5); + } + } + std::transform(key.begin(), key.end(), key.begin(), ::tolower); + result[key] = op; + } + return result; +} diff --git a/test/set_parser_test/setparsertest.cpp b/test/set_parser_test/setparsertest.cpp index 499cffa81..22ef30499 100644 --- a/test/set_parser_test/setparsertest.cpp +++ b/test/set_parser_test/setparsertest.cpp @@ -124,12 +124,39 @@ static Test time_zone[] = { { "SET @@time_zone = \"Europe/Paris\"", { Expected("time_zone", {"Europe/Paris"}) } }, { "SET @@time_zone = \"+00:00\"", { Expected("time_zone", {"+00:00"}) } }, { "SET @@time_zone = @OLD_TIME_ZONE", { Expected("time_zone", {"@OLD_TIME_ZONE"}) } }, + { "SET @@TIME_ZONE = @OLD_TIME_ZONE", { Expected("time_zone", {"@OLD_TIME_ZONE"}) } }, }; TEST(TestParse, SET_TIME_ZONE) { TestParse(time_zone, arraysize(time_zone), "time_zone"); } +static Test session_track_gtids[] = { + { "SET @@session_track_gtids = OFF", { Expected("session_track_gtids", {"OFF"}) } }, + { "SET @@session_track_gtids = OWN_GTID", { Expected("session_track_gtids", {"OWN_GTID"}) } }, + { "SET @@SESSION.session_track_gtids = OWN_GTID", { Expected("session_track_gtids", {"OWN_GTID"}) } }, + { "SET SESSION session_track_gtids = OWN_GTID", { Expected("session_track_gtids", {"OWN_GTID"}) } }, + { "SET @@session_track_gtids = ALL_GTIDS", { Expected("session_track_gtids", {"ALL_GTIDS"}) } }, + { "SET @@SESSION.session_track_gtids = ALL_GTIDS", { Expected("session_track_gtids", {"ALL_GTIDS"}) } }, + { "SET SESSION session_track_gtids = ALL_GTIDS", { Expected("session_track_gtids", {"ALL_GTIDS"}) } }, +}; + +TEST(TestParse, SET_SESSION_TRACK_GTIDS) { + TestParse(session_track_gtids, arraysize(session_track_gtids), "session_track_gtids"); +} + +static Test character_set_results[] = { + { "SET @@character_set_results = utf8", { Expected("character_set_results", {"utf8"}) } }, + { "SET @@character_set_results = NULL", { Expected("character_set_results", {"NULL"}) } }, + { "SET character_set_results = NULL", { Expected("character_set_results", {"NULL"}) } }, + { "SET @@session.character_set_results = NULL", { Expected("character_set_results", {"NULL"}) } }, + { "SET session character_set_results = NULL", { Expected("character_set_results", {"NULL"}) } }, +}; + +TEST(TestParse, SET_CHARACTER_SET_RESULTS) { + TestParse(character_set_results, arraysize(character_set_results), "character_set_results"); +} + static Test names[] = { { "SET NAMES utf8", { Expected("names", {"utf8"}) } }, { "SET NAMES 'utf8'", { Expected("names", {"utf8"}) } }, @@ -140,6 +167,29 @@ static Test names[] = { TEST(TestParse, SET_NAMES) { TestParse(names, arraysize(names), "names"); } +static Test various[] = { + { "SET @@SESSION.SQL_SELECT_LIMIT= DEFAULT", { Expected("sql_select_limit", {"DEFAULT"}) } }, + { "SET @@SQL_SELECT_LIMIT= DEFAULT", { Expected("sql_select_limit", {"DEFAULT"}) } }, + { "SET SESSION SQL_SELECT_LIMIT = DEFAULT", { Expected("sql_select_limit", {"DEFAULT"}) } }, + { "SET @@SESSION.SQL_SELECT_LIMIT= 1234", { Expected("sql_select_limit", {"1234"}) } }, + { "SET @@SQL_SELECT_LIMIT= 1234", { Expected("sql_select_limit", {"1234"}) } }, + { "SET SESSION SQL_SELECT_LIMIT = 1234", { Expected("sql_select_limit", {"1234"}) } }, + { "SET @@SESSION.SQL_SELECT_LIMIT= 1234", { Expected("sql_select_limit", {"1234"}) } }, + { "SET @@SESSION.SQL_SELECT_LIMIT= @old_sql_select_limit", { Expected("sql_select_limit", {"@old_sql_select_limit"}) } }, + { "SET SQL_SELECT_LIMIT= @old_sql_select_limit", { Expected("sql_select_limit", {"@old_sql_select_limit"}) } }, + { "SET @@SESSION.sql_auto_is_null = 0", { Expected("sql_auto_is_null", {"0"}) } }, + { "SET SESSION sql_auto_is_null = 1", { Expected("sql_auto_is_null", {"1"}) } }, + { "SET sql_auto_is_null = OFF", { Expected("sql_auto_is_null", {"OFF"}) } }, + { "SET @@sql_auto_is_null = ON", { Expected("sql_auto_is_null", {"ON"}) } }, + { "SET @@SESSION.sql_safe_updates = 0", { Expected("sql_safe_updates", {"0"}) } }, + { "SET SESSION sql_safe_updates = 1", { Expected("sql_safe_updates", {"1"}) } }, + { "SET SQL_SAFE_UPDATES = OFF", { Expected("sql_safe_updates", {"OFF"}) } }, + { "SET @@sql_safe_updates = ON", { Expected("sql_safe_updates", {"ON"}) } }, +}; + +TEST(TestParse, SET_VARIOUS) { + TestParse(various, arraysize(various), "various"); +} static Test multiple[] = { { "SET time_zone = 'Europe/Paris', sql_mode = 'TRADITIONAL'", { Expected("time_zone", {"Europe/Paris"}), Expected("sql_mode", {"TRADITIONAL"}) } },