set names optimization

pull/2650/head
val 6 years ago
parent d0d7018e34
commit 66788863b3

@ -119,6 +119,7 @@ class MySQL_Session
bool handler_again___status_SETTING_LDAP_USER_VARIABLE(int *);
bool handler_again___status_SETTING_SQL_MODE(int *);
bool handler_again___status_SETTING_SESSION_TRACK_GTIDS(int *);
bool handler_again___status_CHANGING_CHARSET(int *_rc);
bool handler_again___status_CHANGING_SCHEMA(int *);
bool handler_again___status_CONNECTING_SERVER(int *);
bool handler_again___status_CHANGING_USER_SERVER(int *);

@ -2092,6 +2092,80 @@ bool MySQL_Session::handler_again___status_SETTING_SQL_LOG_BIN(int *_rc) {
return ret;
}
bool MySQL_Session::handler_again___status_CHANGING_CHARSET(int *_rc) {
assert(mybe->server_myds->myconn);
MySQL_Data_Stream *myds=mybe->server_myds;
MySQL_Connection *myconn=myds->myconn;
char msg[128];
const MARIADB_CHARSET_INFO *ci = NULL;
const char* replace_collation = "";
const char* not_supported_collation = "";
/* Validate that server can support client's charset */
if (!validate_charset(this, SQL_CHARACTER_SET_CLIENT, *_rc)) {
return false;
}
myds->DSS=STATE_MARIADB_QUERY;
enum session_status st=status;
if (myds->mypolls==NULL) {
thread->mypolls.add(POLLIN|POLLOUT, mybe->server_myds->fd, mybe->server_myds, thread->curtime);
}
mysql_variables.client_set_value(this, SQL_CHARACTER_SET, mysql_variables.client_get_value(this, SQL_CHARACTER_SET_CLIENT));
int charset = atoi(mysql_variables.client_get_value(this, SQL_CHARACTER_SET_CLIENT));
int rc=myconn->async_set_names(myds->revents, 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);
} else {
if (rc==-1) {
// the command failed
int myerr=mysql_errno(myconn->mysql);
if (myerr >= 2000) {
if (myerr == 2019) {
proxy_error("Client trying to set a charset/collation (%u) not supported by backend (%s:%d). Changing it to %u\n", charset, myconn->parent->address, myconn->parent->port, mysql_tracked_variables[SQL_CHARACTER_SET].default_value);
}
bool retry_conn=false;
// client error, serious
proxy_error("Detected a broken connection during SET NAMES on %s , %d : %d, %s\n", myconn->parent->address, myconn->parent->port, myerr, mysql_error(myconn->mysql));
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;
if (retry_conn) {
myds->DSS=STATE_NOT_INITIALIZED;
//previous_status.push(PROCESSING_QUERY);
NEXT_IMMEDIATE_NEW(CONNECTING_SERVER);
}
*_rc=-1;
return false;
} else {
proxy_warning("Error during SET NAMES: %d, %s\n", 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);
myds->fd=0;
status=WAITING_CLIENT_DATA;
client_myds->DSS=STATE_SLEEP;
RequestEnd(myds);
}
} else {
// rc==1 , nothing to do for now
}
}
return false;
}
bool MySQL_Session::handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, const char *var_name, const char *var_value, bool no_quote, bool set_transaction) {
bool ret = false;
assert(mybe->server_myds->myconn);
@ -3998,6 +4072,17 @@ handler_again:
}
break;
case SETTING_SET_NAMES:
{
int rc=0;
if (handler_again___status_CHANGING_CHARSET(&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_MODE:
case SETTING_SQL_SELECT_LIMIT:
@ -4014,7 +4099,6 @@ handler_again:
case SETTING_NET_WRITE_TIMEOUT:
case SETTING_MAX_JOIN_SIZE:
case SETTING_CHARSET:
case SETTING_SET_NAMES:
case SETTING_SQL_LOG_BIN:
case SETTING_WSREP_SYNC_WAIT:
for (auto i = 0; i < SQL_NAME_LAST; i++) {

@ -325,24 +325,59 @@ bool update_server_variable(MySQL_Session* session, int idx, int &_rc) {
inline bool verify_server_variable(MySQL_Session* session, int idx, uint32_t client_hash, uint32_t server_hash) {
if (client_hash != server_hash) {
switch(session->status) { // this switch can be replaced with a simple previous_status.push(status), but it is here for readibility
case PROCESSING_QUERY:
session->previous_status.push(PROCESSING_QUERY);
break;
case PROCESSING_STMT_PREPARE:
session->previous_status.push(PROCESSING_STMT_PREPARE);
break;
case PROCESSING_STMT_EXECUTE:
session->previous_status.push(PROCESSING_STMT_EXECUTE);
break;
default:
proxy_error("Wrong status %d\n", session->status);
assert(0);
break;
uint32_t client_charset_hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET_CLIENT);
uint32_t results_charset_hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET_RESULTS);
uint32_t connection_charset_hash = mysql_variables.client_get_hash(session, SQL_CHARACTER_SET_CONNECTION);
uint32_t collation_hash = mysql_variables.client_get_hash(session, SQL_COLLATION_CONNECTION);
bool process_charset_variable = ((idx == SQL_CHARACTER_SET_CLIENT) || (idx == SQL_CHARACTER_SET_RESULTS) || (idx == SQL_CHARACTER_SET_CONNECTION) || (idx == SQL_COLLATION_CONNECTION));
bool is_set_names_hash = ((client_charset_hash == results_charset_hash) && (client_charset_hash == connection_charset_hash) && (client_charset_hash == collation_hash));
if (process_charset_variable && is_set_names_hash) {
switch(session->status) { // this switch can be replaced with a simple previous_status.push(status), but it is here for readibility
case PROCESSING_QUERY:
session->previous_status.push(PROCESSING_QUERY);
break;
case PROCESSING_STMT_PREPARE:
session->previous_status.push(PROCESSING_STMT_PREPARE);
break;
case PROCESSING_STMT_EXECUTE:
session->previous_status.push(PROCESSING_STMT_EXECUTE);
break;
default:
proxy_error("Wrong status %d\n", session->status);
assert(0);
break;
}
session->set_status(SETTING_SET_NAMES);
mysql_variables.server_set_value(session, SQL_CHARACTER_SET_CLIENT, mysql_variables.client_get_value(session, SQL_CHARACTER_SET_CLIENT));
mysql_variables.server_set_value(session, SQL_CHARACTER_SET_RESULTS, mysql_variables.client_get_value(session, SQL_CHARACTER_SET_RESULTS));
mysql_variables.server_set_value(session, SQL_CHARACTER_SET_CONNECTION, mysql_variables.client_get_value(session, SQL_CHARACTER_SET_CONNECTION));
mysql_variables.server_set_value(session, SQL_COLLATION_CONNECTION, mysql_variables.client_get_value(session, SQL_COLLATION_CONNECTION));
mysql_variables.client_set_value(session, SQL_CHARACTER_SET, mysql_variables.client_get_value(session, SQL_CHARACTER_SET_CLIENT));
mysql_variables.server_set_value(session, SQL_CHARACTER_SET, mysql_variables.client_get_value(session, SQL_CHARACTER_SET_CLIENT));
return true;
} else {
switch(session->status) { // this switch can be replaced with a simple previous_status.push(status), but it is here for readibility
case PROCESSING_QUERY:
session->previous_status.push(PROCESSING_QUERY);
break;
case PROCESSING_STMT_PREPARE:
session->previous_status.push(PROCESSING_STMT_PREPARE);
break;
case PROCESSING_STMT_EXECUTE:
session->previous_status.push(PROCESSING_STMT_EXECUTE);
break;
default:
proxy_error("Wrong status %d\n", session->status);
assert(0);
break;
}
session->set_status(mysql_tracked_variables[idx].status);
mysql_variables.server_set_value(session, idx, mysql_variables.client_get_value(session, idx));
return true;
}
session->set_status(mysql_tracked_variables[idx].status);
mysql_variables.server_set_value(session, idx, mysql_variables.client_get_value(session, idx));
return true;
}
return false;
}

Loading…
Cancel
Save