Skip to content

Commit a098f46

Browse files
committed
Bug #17309863 AUTO RECONNECT DOES NOT WORK WITH 5.6 LIBMYSQLCLIENT
Problem Statement: Automatic reconnection does not work for MySQL client programs linked with 5.6 libmysqlclient, even if MYSQL_OPT_RECONNECT is enabled. Analysis: When we have two connections (say con_1 and con_2) in which 'con_1' has auto-reconnect enabled. In such case if 'con_2' sends 'KILL <con_1 id>' (killing 'con_1'), then the server closes the socket for 'con_1'. After that when we send any query to 'con_1' it is failing with "Lost connection to MySQL server during query" error, even though auto-reconnect is enabled for 'con_1'. This is because send() which sends query might still succeed on client even though connection has been already closed on server. Since send() returns success at client side, client tries to recv() the data. Now client receives '0' means that the peer has closed the connection. Hence the query fails with the error mentioned above. Problem didn't exist in 5.5 and earlier versions because in them we tried to read-up all data remaining from previous command before sending new one to the server. As result we detected that connection was closed before query was sent and re-established connection. Fix: Check if socket is alive using vio_is_connected() call in case if auto-reconnect is enabled before sending query to server. If socket was disconnected by server set net->error to 2 so the socket on the client will be closed as well and reconnect will be initiated before sending the query. Reconnect doesn't make sense in case of COM_QUIT so skip the connection check for this command. Note: This fix doesn't solve the problem fully as bug still can occur if connection is killed exactly after this check and before query is sent. But this is acceptable since similar problem exists in 5.5. Also note that this patch might cause slight performance degradation, but it affects only auto-reconnect mode and therefore acceptable.
1 parent 752f93f commit a098f46

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

sql-common/client.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,20 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
724724
*/
725725
net_clear(&mysql->net, (command != COM_QUIT));
726726

727+
#if !defined(EMBEDDED_LIBRARY)
728+
/*
729+
If auto-reconnect mode is enabled check if connection is still alive before
730+
sending new command. Otherwise, send() might not notice that connection was
731+
closed by the server (for example, due to KILL statement), and the fact that
732+
connection is gone will be noticed only on attempt to read command's result,
733+
when it is too late to reconnect. Note that such scenario can still occur if
734+
connection gets killed after this check but before command is sent to
735+
server. But this should be rare.
736+
*/
737+
if ((command != COM_QUIT) && mysql->reconnect && !vio_is_connected(net->vio))
738+
net->error= 2;
739+
#endif
740+
727741
if (net_write_command(net,(uchar) command, header, header_length,
728742
arg, arg_length))
729743
{

tests/mysql_client_test.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19301,6 +19301,57 @@ static void test_wl6587()
1930119301
myquery(rc);
1930219302
}
1930319303

19304+
#ifndef EMBEDDED_LIBRARY
19305+
/*
19306+
Bug #17309863 AUTO RECONNECT DOES NOT WORK WITH 5.6 LIBMYSQLCLIENT
19307+
*/
19308+
static void test_bug17309863()
19309+
{
19310+
MYSQL *lmysql;
19311+
unsigned long thread_id;
19312+
char query[MAX_TEST_QUERY_LENGTH];
19313+
int rc;
19314+
19315+
myheader("test_bug17309863");
19316+
19317+
if (!opt_silent)
19318+
fprintf(stdout, "\n Establishing a test connection ...");
19319+
if (!(lmysql= mysql_client_init(NULL)))
19320+
{
19321+
myerror("mysql_client_init() failed");
19322+
exit(1);
19323+
}
19324+
lmysql->reconnect= 1;
19325+
if (!(mysql_real_connect(lmysql, opt_host, opt_user,
19326+
opt_password, current_db, opt_port,
19327+
opt_unix_socket, 0)))
19328+
{
19329+
myerror("connection failed");
19330+
exit(1);
19331+
}
19332+
if (!opt_silent)
19333+
fprintf(stdout, "OK");
19334+
19335+
thread_id= mysql_thread_id(lmysql);
19336+
sprintf(query, "KILL %lu", thread_id);
19337+
19338+
/*
19339+
Running the "KILL <thread_id>" query in a separate connection.
19340+
*/
19341+
if (thread_query(query))
19342+
exit(1);
19343+
19344+
/*
19345+
The above KILL statement should have closed our connection. But reconnect
19346+
flag allows to detect this before sending query and re-establish it without
19347+
returning an error.
19348+
*/
19349+
rc= mysql_query(lmysql, "SELECT 'bug17309863'");
19350+
myquery(rc);
19351+
19352+
mysql_close(lmysql);
19353+
}
19354+
#endif
1930419355

1930519356
static struct my_tests_st my_tests[]= {
1930619357
{ "disable_query_logs", disable_query_logs },
@@ -19573,6 +19624,9 @@ static struct my_tests_st my_tests[]= {
1957319624
{ "test_wl5968", test_wl5968 },
1957419625
{ "test_wl5924", test_wl5924 },
1957519626
{ "test_wl6587", test_wl6587 },
19627+
#ifndef EMBEDDED_LIBRARY
19628+
{ "test_bug17309863", test_bug17309863},
19629+
#endif
1957619630
{ 0, 0 }
1957719631
};
1957819632

0 commit comments

Comments
 (0)