Track NO_BACKSLASH_ESCAPES #1738

`SERVER_STATUS_NO_BACKSLASH_ESCAPES` is now tracked.
`set sql_mode` is executed immediately if client executes `set sql_mode`
specifying `NO_BACKSLASH_ESCAPES`.
A backend connection with `SERVER_STATUS_NO_BACKSLASH_ESCAPES` enabled has multiplexing immediately disabled.
pull/2026/head
René Cannaò 7 years ago
parent 33fbacd0c2
commit 9788643f38

@ -225,6 +225,7 @@ class MySQL_Session
void Memory_Stats();
void create_new_session_and_reset_connection(MySQL_Data_Stream *_myds);
bool handle_command_query_kill(PtrSize_t *);
void finishQuery(MySQL_Data_Stream *myds, MySQL_Connection *myconn, bool);
};
#define KILL_QUERY 1

@ -14,6 +14,7 @@
#define STATUS_MYSQL_CONNECTION_NO_MULTIPLEX 0x00000080
#define STATUS_MYSQL_CONNECTION_SQL_LOG_BIN0 0x00000100
#define STATUS_MYSQL_CONNECTION_FOUND_ROWS 0x00000200
#define STATUS_MYSQL_CONNECTION_NO_BACKSLASH_ESCAPES 0x00000400
class MySQL_Connection_userinfo {
private:
@ -57,6 +58,7 @@ class MySQL_Connection {
uint8_t sql_log_bin;
int8_t last_set_autocommit;
bool autocommit;
bool no_backslash_escapes;
} options;
struct {
unsigned long length;
@ -103,6 +105,7 @@ class MySQL_Connection {
MySQL_Connection();
~MySQL_Connection();
bool set_autocommit(bool);
bool set_no_backslash_escapes(bool);
uint8_t set_charset(uint8_t);
void set_status_transaction(bool);
@ -110,6 +113,7 @@ class MySQL_Connection {
void set_status_get_lock(bool);
void set_status_lock_tables(bool);
void set_status_temporary_table(bool);
void set_status_no_backslash_escapes(bool);
void set_status_prepared_statement(bool);
void set_status_user_variable(bool);
void set_status_no_multiplex(bool);
@ -120,6 +124,7 @@ class MySQL_Connection {
bool get_status_get_lock();
bool get_status_lock_tables();
bool get_status_temporary_table();
bool get_status_no_backslash_escapes();
bool get_status_prepared_statement();
bool get_status_user_variable();
bool get_status_no_multiplex();

@ -509,6 +509,11 @@ bool MySQL_Protocol::generate_pkt_EOF(bool send, void **ptr, unsigned int *len,
break;
}
}
if (*myds && (*myds)->myconn) {
if ((*myds)->myconn->options.no_backslash_escapes) {
internal_status += SERVER_STATUS_NO_BACKSLASH_ESCAPES;
}
}
memcpy(_ptr+l, &warnings, sizeof(uint16_t)); l+=sizeof(uint16_t);
memcpy(_ptr+l, &internal_status, sizeof(uint16_t));
@ -618,6 +623,11 @@ bool MySQL_Protocol::generate_pkt_OK(bool send, void **ptr, unsigned int *len, u
break;
}
}
if (*myds && (*myds)->myconn) {
if ((*myds)->myconn->options.no_backslash_escapes) {
internal_status += SERVER_STATUS_NO_BACKSLASH_ESCAPES;
}
}
memcpy(_ptr+l, &internal_status, sizeof(uint16_t)); l+=sizeof(uint16_t);
memcpy(_ptr+l, &warnings, sizeof(uint16_t)); l+=sizeof(uint16_t);
if (msg && strlen(msg)) {

@ -1727,6 +1727,30 @@ bool MySQL_Session::handler_again___status_SETTING_SQL_MODE(int *_rc) {
myds->revents|=POLLOUT; // we also set again POLLOUT to send a query immediately!
st=previous_status.top();
previous_status.pop();
bool nbe = (myconn->mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES);
if (client_myds) {
client_myds->myconn->set_no_backslash_escapes(nbe);
}
if (nbe) {
myconn->set_status_no_backslash_escapes(nbe);
}
if (st == PROCESSING_QUERY) { // only TEXT protocol, no prepared statements
if (client_myds && mirror==false) {
if (CurrentQuery.QueryParserArgs.digest_text) {
// this is not meant to match all the SET SQL_MODE, but just to
// reduce unnecessary SET SQL_MODE when possible
if (strncasecmp(CurrentQuery.QueryParserArgs.digest_text,(char *)"set sql_mode",12)==0) {
unsigned int nTrx=NumActiveTransactions();
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);
RequestEnd(myds);
finishQuery(myds,myconn,false);
return ret;
}
}
}
}
NEXT_IMMEDIATE_NEW(st);
} else {
if (rc==-1) {
@ -3129,52 +3153,7 @@ handler_again:
}
RequestEnd(myds);
myds->myconn->reduce_auto_increment_delay_token();
if (mysql_thread___multiplexing && (myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) {
if (mysql_thread___connection_delay_multiplex_ms && mirror==false) {
myds->wait_until=thread->curtime+mysql_thread___connection_delay_multiplex_ms*1000;
myconn->async_state_machine=ASYNC_IDLE;
myconn->multiplex_delayed=true;
myds->DSS=STATE_MARIADB_GENERIC;
} else if (prepared_stmt_with_no_params==true) { // see issue #1432
myconn->async_state_machine=ASYNC_IDLE;
myds->DSS=STATE_MARIADB_GENERIC;
myds->wait_until=0;
myconn->multiplex_delayed=false;
} else {
myconn->multiplex_delayed=false;
myds->wait_until=0;
myds->DSS=STATE_NOT_INITIALIZED;
if (mysql_thread___autocommit_false_not_reusable && myds->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();
}
}
if (transaction_persistent==true) {
transaction_persistent_hostgroup=-1;
}
} else {
myconn->multiplex_delayed=false;
myconn->compute_unknown_transaction_status();
myconn->async_state_machine=ASYNC_IDLE;
myds->DSS=STATE_MARIADB_GENERIC;
if (transaction_persistent==true) {
if (transaction_persistent_hostgroup==-1) { // change only if not set already, do not allow to change it again
if (myds->myconn->IsActiveTransaction()==true) { // only active transaction is important here. Ignore other criterias
transaction_persistent_hostgroup=current_hostgroup;
}
} else {
if (myds->myconn->IsActiveTransaction()==false) { // a transaction just completed
transaction_persistent_hostgroup=-1;
}
}
}
}
finishQuery(myds,myconn,prepared_stmt_with_no_params);
} else {
if (rc==-1) {
int myerr=mysql_errno(myconn->mysql);
@ -4302,6 +4281,9 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C
}
proxy_debug(PROXY_DEBUG_MYSQL_COM, 8, "Changing connection SQL Mode to %s\n", value1.c_str());
client_myds->myconn->options.sql_mode=strdup(value1.c_str());
if (strcasestr(value1.c_str(), (char *)"NO_BACKSLASH_ESCAPES")) {
goto __exit_set_destination_hostgroup;
}
}
} else if (var == "time_zone") {
std::string value1 = *values;
@ -5191,3 +5173,52 @@ void MySQL_Session::add_ldap_comment_to_pkt(PtrSize_t *_pkt) {
_pkt->size = _pkt->size + strlen(b);
_pkt->ptr = _new_pkt.ptr;
}
void MySQL_Session::finishQuery(MySQL_Data_Stream *myds, MySQL_Connection *myconn, bool prepared_stmt_with_no_params) {
myds->myconn->reduce_auto_increment_delay_token();
if (mysql_thread___multiplexing && (myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) {
if (mysql_thread___connection_delay_multiplex_ms && mirror==false) {
myds->wait_until=thread->curtime+mysql_thread___connection_delay_multiplex_ms*1000;
myconn->async_state_machine=ASYNC_IDLE;
myconn->multiplex_delayed=true;
myds->DSS=STATE_MARIADB_GENERIC;
} else if (prepared_stmt_with_no_params==true) { // see issue #1432
myconn->async_state_machine=ASYNC_IDLE;
myds->DSS=STATE_MARIADB_GENERIC;
myds->wait_until=0;
myconn->multiplex_delayed=false;
} else {
myconn->multiplex_delayed=false;
myds->wait_until=0;
myds->DSS=STATE_NOT_INITIALIZED;
if (mysql_thread___autocommit_false_not_reusable && myds->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();
}
}
if (transaction_persistent==true) {
transaction_persistent_hostgroup=-1;
}
} else {
myconn->multiplex_delayed=false;
myconn->compute_unknown_transaction_status();
myconn->async_state_machine=ASYNC_IDLE;
myds->DSS=STATE_MARIADB_GENERIC;
if (transaction_persistent==true) {
if (transaction_persistent_hostgroup==-1) { // change only if not set already, do not allow to change it again
if (myds->myconn->IsActiveTransaction()==true) { // only active transaction is important here. Ignore other criterias
transaction_persistent_hostgroup=current_hostgroup;
}
} else {
if (myds->myconn->IsActiveTransaction()==false) { // a transaction just completed
transaction_persistent_hostgroup=-1;
}
}
}
}
}

@ -202,6 +202,7 @@ MySQL_Connection::MySQL_Connection() {
options.server_version=NULL;
options.last_set_autocommit=-1; // -1 = never set
options.autocommit=true;
options.no_backslash_escapes=false;
options.init_connect=NULL;
options.init_connect_sent=false;
options.ldap_user_variable=NULL;
@ -279,6 +280,12 @@ bool MySQL_Connection::set_autocommit(bool _ac) {
return _ac;
}
bool MySQL_Connection::set_no_backslash_escapes(bool _ac) {
proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 4, "Setting no_backslash_escapes %d\n", _ac);
options.no_backslash_escapes=_ac;
return _ac;
}
uint8_t MySQL_Connection::set_charset(uint8_t _c) {
proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 4, "Setting charset %d\n", _c);
options.charset=_c;
@ -339,6 +346,14 @@ void MySQL_Connection::set_status_temporary_table(bool v) {
}
}
void MySQL_Connection::set_status_no_backslash_escapes(bool v) {
if (v) {
status_flags |= STATUS_MYSQL_CONNECTION_NO_BACKSLASH_ESCAPES;
} else {
status_flags &= ~STATUS_MYSQL_CONNECTION_NO_BACKSLASH_ESCAPES;
}
}
void MySQL_Connection::set_status_user_variable(bool v) {
if (v) {
status_flags |= STATUS_MYSQL_CONNECTION_USER_VARIABLE;
@ -402,6 +417,10 @@ bool MySQL_Connection::get_status_temporary_table() {
return status_flags & STATUS_MYSQL_CONNECTION_TEMPORARY_TABLE;
}
bool MySQL_Connection::get_status_no_backslash_escapes() {
return status_flags & STATUS_MYSQL_CONNECTION_NO_BACKSLASH_ESCAPES;
}
bool MySQL_Connection::get_status_prepared_statement() {
return status_flags & STATUS_MYSQL_CONNECTION_PREPARED_STATEMENT;
}
@ -1631,7 +1650,7 @@ bool MySQL_Connection::MultiplexDisabled() {
// status_flags stores information about the status of the connection
// can be used to determine if multiplexing can be enabled or not
bool ret=false;
if (status_flags & (STATUS_MYSQL_CONNECTION_TRANSACTION|STATUS_MYSQL_CONNECTION_USER_VARIABLE|STATUS_MYSQL_CONNECTION_PREPARED_STATEMENT|STATUS_MYSQL_CONNECTION_LOCK_TABLES|STATUS_MYSQL_CONNECTION_TEMPORARY_TABLE|STATUS_MYSQL_CONNECTION_GET_LOCK|STATUS_MYSQL_CONNECTION_NO_MULTIPLEX|STATUS_MYSQL_CONNECTION_SQL_LOG_BIN0|STATUS_MYSQL_CONNECTION_FOUND_ROWS) ) {
if (status_flags & (STATUS_MYSQL_CONNECTION_TRANSACTION|STATUS_MYSQL_CONNECTION_USER_VARIABLE|STATUS_MYSQL_CONNECTION_PREPARED_STATEMENT|STATUS_MYSQL_CONNECTION_LOCK_TABLES|STATUS_MYSQL_CONNECTION_TEMPORARY_TABLE|STATUS_MYSQL_CONNECTION_GET_LOCK|STATUS_MYSQL_CONNECTION_NO_MULTIPLEX|STATUS_MYSQL_CONNECTION_SQL_LOG_BIN0|STATUS_MYSQL_CONNECTION_FOUND_ROWS|STATUS_MYSQL_CONNECTION_NO_BACKSLASH_ESCAPES) ) {
ret=true;
}
if (auto_increment_delay_token) return true;

Loading…
Cancel
Save