diff --git a/include/mysql_connection.h b/include/mysql_connection.h index 4f7573cd3..a0bb1f5e3 100644 --- a/include/mysql_connection.h +++ b/include/mysql_connection.h @@ -92,6 +92,8 @@ class MySQL_Connection { bool processing_prepared_statement_execute; bool processing_multi_statement; bool multiplex_delayed; + bool unknown_transaction_status; + void compute_unknown_transaction_status(); MySQL_Connection(); ~MySQL_Connection(); bool set_autocommit(bool); diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index c5862fb95..14d8b3467 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -942,6 +942,7 @@ int MySQL_Session::handler_again___status_PINGING_SERVER() { int rc=myconn->async_ping(myds->revents); if (rc==0) { myconn->async_state_machine=ASYNC_IDLE; + myconn->unknown_transaction_status = false; if (mysql_thread___multiplexing && (myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { myds->return_MySQL_Connection_To_Pool(); } else { @@ -2730,6 +2731,7 @@ handler_again: enum session_status st=status; size_t sts=previous_status.size(); if (sts) { + myconn->unknown_transaction_status = false; myconn->async_state_machine=ASYNC_IDLE; myds->DSS=STATE_MARIADB_GENERIC; st=previous_status.top(); @@ -2769,6 +2771,7 @@ handler_again: 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->unknown_transaction_status = false; myconn->async_state_machine=ASYNC_IDLE; myconn->multiplex_delayed=true; myds->DSS=STATE_MARIADB_GENERIC; @@ -2796,6 +2799,7 @@ handler_again: } } else { myconn->multiplex_delayed=false; + myconn->unknown_transaction_status = false; myconn->async_state_machine=ASYNC_IDLE; myds->DSS=STATE_MARIADB_GENERIC; if (transaction_persistent==true) { @@ -2813,6 +2817,7 @@ handler_again: } else { if (rc==-1) { int myerr=mysql_errno(myconn->mysql); + myconn->compute_unknown_transaction_status(); char *errmsg = NULL; if (myerr == 0) { if (CurrentQuery.mysql_stmt) { diff --git a/lib/mysql_connection.cpp b/lib/mysql_connection.cpp index e566f10aa..d88b517cc 100644 --- a/lib/mysql_connection.cpp +++ b/lib/mysql_connection.cpp @@ -49,6 +49,29 @@ MySQL_Connection_userinfo::~MySQL_Connection_userinfo() { if (schemaname) free(schemaname); } +void MySQL_Connection::compute_unknown_transaction_status() { + if (mysql) { + int _myerrno=mysql_errno(mysql); + if (_myerrno == 0) { + unknown_transaction_status = false; // no error + return; + } + if (_myerrno >= 2000 && _myerrno < 3000) { // client error + // do not change it + return; + } + if (_myerrno >= 1000 && _myerrno < 2000) { // server error + unknown_transaction_status = true; + return; + } + if (_myerrno >= 3000 && _myerrno < 4000) { // server error + unknown_transaction_status = true; + return; + } + // all other cases, server error + } +} + uint64_t MySQL_Connection_userinfo::compute_hash() { int l=0; if (username) @@ -189,6 +212,7 @@ MySQL_Connection::MySQL_Connection() { largest_query_length=0; multiplex_delayed=false; MyRS=NULL; + unknown_transaction_status = false; creation_time=0; processing_multi_statement=false; proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 4, "Creating new MySQL_Connection %p\n", this); @@ -981,6 +1005,14 @@ handler_again: } break; case ASYNC_QUERY_END: + if (mysql) { + int _myerrno=mysql_errno(mysql); + if (_myerrno == 0) { + unknown_transaction_status = false; + } else { + compute_unknown_transaction_status(); + } + } if (mysql_result) { mysql_free_result(mysql_result); mysql_result=NULL; @@ -1137,6 +1169,7 @@ int MySQL_Connection::async_connect(short event) { return 0; } if (async_state_machine==ASYNC_CONNECT_SUCCESSFUL) { + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; myds->wait_until=0; creation_time = monotonic_time(); @@ -1145,6 +1178,7 @@ int MySQL_Connection::async_connect(short event) { handler(event); switch (async_state_machine) { case ASYNC_CONNECT_SUCCESSFUL: + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; myds->wait_until=0; return 0; @@ -1224,8 +1258,10 @@ int MySQL_Connection::async_query(short event, char *stmt, unsigned long length, if (async_state_machine==ASYNC_QUERY_END) { if (mysql_errno(mysql)) { + compute_unknown_transaction_status(); return -1; } else { + unknown_transaction_status = false; return 0; } } @@ -1233,17 +1269,21 @@ int MySQL_Connection::async_query(short event, char *stmt, unsigned long length, query.stmt_meta=NULL; async_state_machine=ASYNC_QUERY_END; if (mysql_stmt_errno(query.stmt)) { + compute_unknown_transaction_status(); return -1; } else { + unknown_transaction_status = false; return 0; } } if (async_state_machine==ASYNC_STMT_PREPARE_SUCCESSFUL || async_state_machine==ASYNC_STMT_PREPARE_FAILED) { query.stmt_meta=NULL; if (async_state_machine==ASYNC_STMT_PREPARE_FAILED) { + compute_unknown_transaction_status(); return -1; } else { *_stmt=query.stmt; + unknown_transaction_status = false; return 0; } } @@ -1273,6 +1313,7 @@ int MySQL_Connection::async_ping(short event) { assert(ret_mysql); switch (async_state_machine) { case ASYNC_PING_SUCCESSFUL: + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; return 0; break; @@ -1292,6 +1333,7 @@ int MySQL_Connection::async_ping(short event) { // check again switch (async_state_machine) { case ASYNC_PING_SUCCESSFUL: + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; return 0; break; @@ -1314,6 +1356,7 @@ int MySQL_Connection::async_change_user(short event) { assert(ret_mysql); switch (async_state_machine) { case ASYNC_CHANGE_USER_SUCCESSFUL: + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; return 0; break; @@ -1333,6 +1376,7 @@ int MySQL_Connection::async_change_user(short event) { // check again switch (async_state_machine) { case ASYNC_CHANGE_USER_SUCCESSFUL: + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; return 0; break; @@ -1355,6 +1399,7 @@ int MySQL_Connection::async_select_db(short event) { assert(ret_mysql); switch (async_state_machine) { case ASYNC_INITDB_SUCCESSFUL: + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; return 0; break; @@ -1371,6 +1416,7 @@ int MySQL_Connection::async_select_db(short event) { // check again switch (async_state_machine) { case ASYNC_INITDB_SUCCESSFUL: + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; return 0; break; @@ -1390,6 +1436,7 @@ int MySQL_Connection::async_set_autocommit(short event, bool ac) { assert(ret_mysql); switch (async_state_machine) { case ASYNC_SET_AUTOCOMMIT_SUCCESSFUL: + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; return 0; break; @@ -1407,6 +1454,7 @@ int MySQL_Connection::async_set_autocommit(short event, bool ac) { // check again switch (async_state_machine) { case ASYNC_SET_AUTOCOMMIT_SUCCESSFUL: + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; return 0; break; @@ -1426,6 +1474,7 @@ int MySQL_Connection::async_set_names(short event, uint8_t c) { assert(ret_mysql); switch (async_state_machine) { case ASYNC_SET_NAMES_SUCCESSFUL: + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; return 0; break; @@ -1443,6 +1492,7 @@ int MySQL_Connection::async_set_names(short event, uint8_t c) { // check again switch (async_state_machine) { case ASYNC_SET_NAMES_SUCCESSFUL: + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; return 0; break; @@ -1487,6 +1537,7 @@ void MySQL_Connection::async_free_result() { mysql_result=NULL; } } + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; if (MyRS) { delete MyRS; @@ -1499,7 +1550,7 @@ bool MySQL_Connection::IsActiveTransaction() { bool ret=false; if (mysql) { ret = (mysql->server_status & SERVER_STATUS_IN_TRANS); - if (ret == false && (mysql)->net.last_errno) { + if (ret == false && (mysql)->net.last_errno && unknown_transaction_status == true) { ret = true; } if (ret == false) { @@ -1685,8 +1736,10 @@ int MySQL_Connection::async_send_simple_command(short event, char *stmt, unsigne } if (async_state_machine==ASYNC_QUERY_END) { if (mysql_errno(mysql)) { + compute_unknown_transaction_status(); return -1; } else { + unknown_transaction_status = false; async_state_machine=ASYNC_IDLE; return 0; }