summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <kostja@bodhi.local>2006-07-24 14:56:53 +0400
committerunknown <kostja@bodhi.local>2006-07-24 14:56:53 +0400
commit36510232aa5ab3788de36d17202254e3789441f4 (patch)
tree9e665cae0cf874da93929345fdbe6d3d6d97debb
parent12d6b9c7f131cd623e384b8f176806d5e5dac7e2 (diff)
downloadmariadb-git-36510232aa5ab3788de36d17202254e3789441f4.tar.gz
A fix and a test case for Bug#15752 "Lost connection to MySQL server
when calling a SP from C API" The bug was caused by lack of checks for misuse in mysql_real_query. A stored procedure always returns at least one result, which is the status of execution of the procedure itself. This result, or so-called OK packet, is similar to a result returned by INSERT/UPDATE/CREATE operations: it contains the overall status of execution, the number of affected rows and the number of warnings. The client test program attached to the bug did not read this result and ivnoked the next query. In turn, libmysql had no check for such scenario and mysql_real_query was simply trying to send that query without reading the pending response, thus messing up the communication protocol. The fix is to return an error from mysql_real_query when it's called prior to retrieval of all pending results. client/mysqlbinlog.cc: net_safe_read -> cli_safe_read include/mysql.h: Remove a private function from the public header. include/mysql_com.h: Remove a define that is never used. include/sql_common.h: Add a declaration for cli_safe_read - a function that reads one packet from the server. libmysql/libmysql.c: net_safe_read -> cli_safe_read Return CR_COMMANDS_OUT_OF_SYNC on attempt to execute a statement using a connection which has pending result sets. sql-common/client.c: Actual fix for Bug#15752: if the server has pending result sets for the client, return CR_COMMANDS_OUT_OF_SYNC on attempt to execute another query. Similarly to the behaviour of mysql_use_result(), multiple result sets block the connection and must be fetched before it can be used for another query. This uncovered an error in the protocol: the server doesn't drop SERVER_MORE_RESULTS_EXISTS status flag upon an error, so in case of a multi-query like SELECT 1; SELECT syntax_error; SELECT 2; the client has no way to know that the server won't ever come to execution of the third query and won't return any result sets for it. For now, fix it in cli_safe_read, as a proper fix requires extension of the client-server protocol. sql/protocol.cc: Remove a name that is never used. sql/slave.cc: net_safe_read -> cli_safe_read tests/mysql_client_test.c: Make 'query' a local variable to avoid name clash. Add a test case for Bug#15752 "Lost connection to MySQL server when calling an SP from C API"
-rw-r--r--client/mysqlbinlog.cc3
-rw-r--r--include/mysql.h1
-rw-r--r--include/mysql_com.h1
-rw-r--r--include/sql_common.h2
-rw-r--r--libmysql/libmysql.c16
-rw-r--r--sql-common/client.c69
-rw-r--r--sql/protocol.cc2
-rw-r--r--sql/slave.cc2
-rw-r--r--tests/mysql_client_test.c98
9 files changed, 150 insertions, 44 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 518ab7cf832..9cecdb4eafc 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -36,6 +36,7 @@
/* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
#include "mysql_priv.h"
#include "log_event.h"
+#include "sql_common.h"
#define BIN_LOG_HEADER_SIZE 4
#define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4)
@@ -1077,7 +1078,7 @@ could be out of memory");
const char *error_msg;
Log_event *ev;
- len = net_safe_read(mysql);
+ len= cli_safe_read(mysql);
if (len == packet_error)
{
fprintf(stderr, "Got error reading packet from server: %s\n",
diff --git a/include/mysql.h b/include/mysql.h
index 3a71e47f414..ae5cf670ec9 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -837,7 +837,6 @@ int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB);
#define simple_command(mysql, command, arg, length, skip_check) \
(*(mysql)->methods->advanced_command)(mysql, command, \
NullS, 0, arg, length, skip_check)
-unsigned long net_safe_read(MYSQL* mysql);
#ifdef __NETWARE__
#pragma pack(pop) /* restore alignment */
diff --git a/include/mysql_com.h b/include/mysql_com.h
index ec1c133799f..60e726396cb 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -140,7 +140,6 @@ enum enum_server_command
#define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */
#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */
-#define SERVER_STATUS_MORE_RESULTS 4 /* More results on server */
#define SERVER_MORE_RESULTS_EXISTS 8 /* Multi query - next query exists */
#define SERVER_QUERY_NO_GOOD_INDEX_USED 16
#define SERVER_QUERY_NO_INDEX_USED 32
diff --git a/include/sql_common.h b/include/sql_common.h
index 9fc8d4f457b..c77a905aeb1 100644
--- a/include/sql_common.h
+++ b/include/sql_common.h
@@ -35,7 +35,7 @@ my_bool
cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
const char *header, ulong header_length,
const char *arg, ulong arg_length, my_bool skip_check);
-
+unsigned long cli_safe_read(MYSQL *mysql);
void set_stmt_errmsg(MYSQL_STMT * stmt, const char *err, int errcode,
const char *sqlstate);
void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate);
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index a851d62b108..884c0b3a4db 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -645,7 +645,7 @@ int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd)
NET *net= &mysql->net;
ulong pkt_length;
- pkt_length= net_safe_read(mysql);
+ pkt_length= cli_safe_read(mysql);
if (pkt_length == packet_error)
return 1;
@@ -666,7 +666,7 @@ int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd)
return 1;
}
/* Read what server thinks about out new auth message report */
- if (net_safe_read(mysql) == packet_error)
+ if (cli_safe_read(mysql) == packet_error)
return 1;
}
return 0;
@@ -1887,7 +1887,7 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
DBUG_ENTER("cli_read_prepare_result");
mysql= mysql->last_used_con;
- if ((packet_length= net_safe_read(mysql)) == packet_error)
+ if ((packet_length= cli_safe_read(mysql)) == packet_error)
DBUG_RETURN(1);
mysql->warning_count= 0;
@@ -2505,7 +2505,8 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
if (stmt->param_count)
{
- NET *net= &stmt->mysql->net;
+ MYSQL *mysql= stmt->mysql;
+ NET *net= &mysql->net;
MYSQL_BIND *param, *param_end;
char *param_data;
ulong length;
@@ -2517,7 +2518,8 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
set_stmt_error(stmt, CR_PARAMS_NOT_BOUND, unknown_sqlstate);
DBUG_RETURN(1);
}
- if (stmt->mysql->status != MYSQL_STATUS_READY)
+ if (mysql->status != MYSQL_STATUS_READY ||
+ mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
{
set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
DBUG_RETURN(1);
@@ -4531,7 +4533,7 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
int cli_unbuffered_fetch(MYSQL *mysql, char **row)
{
- if (packet_error == net_safe_read(mysql))
+ if (packet_error == cli_safe_read(mysql))
return 1;
*row= ((mysql->net.read_pos[0] == 254) ? NULL :
@@ -4640,7 +4642,7 @@ int cli_read_binary_rows(MYSQL_STMT *stmt)
mysql= mysql->last_used_con;
- while ((pkt_len= net_safe_read(mysql)) != packet_error)
+ while ((pkt_len= cli_safe_read(mysql)) != packet_error)
{
cp= net->read_pos;
if (cp[0] != 254 || pkt_len >= 8)
diff --git a/sql-common/client.c b/sql-common/client.c
index 31e85475f08..7c5460dd859 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -584,7 +584,7 @@ err:
*****************************************************************************/
ulong
-net_safe_read(MYSQL *mysql)
+cli_safe_read(MYSQL *mysql)
{
NET *net= &mysql->net;
ulong len=0;
@@ -627,6 +627,16 @@ net_safe_read(MYSQL *mysql)
}
else
set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
+ /*
+ Cover a protocol design error: error packet does not
+ contain the server status. Therefore, the client has no way
+ to find out whether there are more result sets of
+ a multiple-result-set statement pending. Luckily, in 5.0 an
+ error always aborts execution of a statement, wherever it is
+ a multi-statement or a stored procedure, so it should be
+ safe to unconditionally turn off the flag here.
+ */
+ mysql->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
DBUG_PRINT("error",("Got error: %d/%s (%s)",
net->last_errno, net->sqlstate, net->last_error));
@@ -652,7 +662,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
NET *net= &mysql->net;
my_bool result= 1;
init_sigpipe_variables
- DBUG_ENTER("cli_advanced_command");
+ DBUG_ENTER("cli_advanced_command");
/* Don't give sigpipe errors if the client doesn't want them */
set_sigpipe(mysql);
@@ -662,7 +672,8 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
if (mysql_reconnect(mysql))
DBUG_RETURN(1);
}
- if (mysql->status != MYSQL_STATUS_READY)
+ if (mysql->status != MYSQL_STATUS_READY ||
+ mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
{
DBUG_PRINT("error",("state: %d", mysql->status));
set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
@@ -701,7 +712,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
}
result=0;
if (!skip_check)
- result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ?
+ result= ((mysql->packet_length=cli_safe_read(mysql)) == packet_error ?
1 : 0);
end:
reset_sigpipe(mysql);
@@ -753,7 +764,7 @@ static void cli_flush_use_result(MYSQL *mysql)
for (;;)
{
ulong pkt_len;
- if ((pkt_len=net_safe_read(mysql)) == packet_error)
+ if ((pkt_len=cli_safe_read(mysql)) == packet_error)
break;
if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
{
@@ -1275,7 +1286,7 @@ MYSQL_DATA *cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
NET *net = &mysql->net;
DBUG_ENTER("cli_read_rows");
- if ((pkt_len= net_safe_read(mysql)) == packet_error)
+ if ((pkt_len= cli_safe_read(mysql)) == packet_error)
DBUG_RETURN(0);
if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
MYF(MY_WME | MY_ZEROFILL))))
@@ -1340,7 +1351,7 @@ MYSQL_DATA *cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
}
}
cur->data[field]=to; /* End of last field */
- if ((pkt_len=net_safe_read(mysql)) == packet_error)
+ if ((pkt_len=cli_safe_read(mysql)) == packet_error)
{
free_rows(result);
DBUG_RETURN(0);
@@ -1372,7 +1383,7 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
uchar *pos, *prev_pos, *end_pos;
NET *net= &mysql->net;
- if ((pkt_len=net_safe_read(mysql)) == packet_error)
+ if ((pkt_len=cli_safe_read(mysql)) == packet_error)
return -1;
if (pkt_len <= 8 && net->read_pos[0] == 254)
{
@@ -1649,23 +1660,23 @@ static MYSQL_RES *cli_use_result(MYSQL *mysql);
static MYSQL_METHODS client_methods=
{
- cli_read_query_result,
- cli_advanced_command,
- cli_read_rows,
- cli_use_result,
- cli_fetch_lengths,
- cli_flush_use_result
+ cli_read_query_result, /* read_query_result */
+ cli_advanced_command, /* advanced_command */
+ cli_read_rows, /* read_rows */
+ cli_use_result, /* use_result */
+ cli_fetch_lengths, /* fetch_lengths */
+ cli_flush_use_result /* flush_use_result */
#ifndef MYSQL_SERVER
- ,cli_list_fields,
- cli_read_prepare_result,
- cli_stmt_execute,
- cli_read_binary_rows,
- cli_unbuffered_fetch,
- NULL,
- cli_read_statistics,
- cli_read_query_result,
- cli_read_change_user_result,
- cli_read_binary_rows
+ ,cli_list_fields, /* list_fields */
+ cli_read_prepare_result, /* read_prepare_result */
+ cli_stmt_execute, /* stmt_execute */
+ cli_read_binary_rows, /* read_binary_rows */
+ cli_unbuffered_fetch, /* unbuffered_fetch */
+ NULL, /* free_embedded_thd */
+ cli_read_statistics, /* read_statistics */
+ cli_read_query_result, /* next_result */
+ cli_read_change_user_result, /* read_change_user_result */
+ cli_read_binary_rows /* read_rows_from_cursor */
#endif
};
@@ -1999,7 +2010,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
Part 1: Connection established, read and parse first packet
*/
- if ((pkt_length=net_safe_read(mysql)) == packet_error)
+ if ((pkt_length=cli_safe_read(mysql)) == packet_error)
goto error;
/* Check if version of protocol matches current one */
@@ -2223,7 +2234,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
OK-packet, or re-request scrambled password.
*/
- if ((pkt_length=net_safe_read(mysql)) == packet_error)
+ if ((pkt_length=cli_safe_read(mysql)) == packet_error)
goto error;
if (pkt_length == 1 && net->read_pos[0] == 254 &&
@@ -2240,7 +2251,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
goto error;
}
/* Read what server thinks about out new auth message report */
- if (net_safe_read(mysql) == packet_error)
+ if (cli_safe_read(mysql) == packet_error)
goto error;
}
@@ -2564,7 +2575,7 @@ static my_bool cli_read_query_result(MYSQL *mysql)
*/
mysql = mysql->last_used_con;
- if ((length = net_safe_read(mysql)) == packet_error)
+ if ((length = cli_safe_read(mysql)) == packet_error)
DBUG_RETURN(1);
free_old_query(mysql); /* Free old result */
#ifdef MYSQL_CLIENT /* Avoid warn of unused labels*/
@@ -2599,7 +2610,7 @@ get_info:
if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
{
int error=handle_local_infile(mysql,(char*) pos);
- if ((length=net_safe_read(mysql)) == packet_error || error)
+ if ((length= cli_safe_read(mysql)) == packet_error || error)
DBUG_RETURN(1);
goto get_info; /* Get info packet */
}
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 650bd8fc58f..f4efb8004ee 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -322,7 +322,7 @@ static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */
254 Marker (1 byte)
warning_count Stored in 2 bytes; New in 4.1 protocol
status_flag Stored in 2 bytes;
- For flags like SERVER_STATUS_MORE_RESULTS
+ For flags like SERVER_MORE_RESULTS_EXISTS
Note that the warning count will not be sent if 'no_flush' is set as
we don't want to report the warning count until all data is sent to the
diff --git a/sql/slave.cc b/sql/slave.cc
index b284f4a6a16..eb578f69cb0 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3051,7 +3051,7 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
return packet_error;
#endif
- len = net_safe_read(mysql);
+ len = cli_safe_read(mysql);
if (len == packet_error || (long) len < 1)
{
if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED)
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 7ad902afb6c..def67e22f00 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -50,7 +50,6 @@ static unsigned int opt_port;
static my_bool tty_password= 0, opt_silent= 0;
static MYSQL *mysql= 0;
-static char query[MAX_TEST_QUERY_LENGTH];
static char current_db[]= "client_test_db";
static unsigned int test_count= 0;
static unsigned int opt_count= 0;
@@ -269,6 +268,7 @@ mysql_simple_prepare(MYSQL *mysql, const char *query)
static void client_connect(ulong flag)
{
int rc;
+ static char query[MAX_TEST_QUERY_LENGTH];
myheader_r("client_connect");
if (!opt_silent)
@@ -326,6 +326,8 @@ static void client_connect(ulong flag)
static void client_disconnect()
{
+ static char query[MAX_TEST_QUERY_LENGTH];
+
myheader_r("client_disconnect");
if (mysql)
@@ -657,6 +659,7 @@ int my_stmt_result(const char *buff)
static void verify_col_data(const char *table, const char *col,
const char *exp_data)
{
+ static char query[MAX_TEST_QUERY_LENGTH];
MYSQL_RES *result;
MYSQL_ROW row;
int rc, field= 1;
@@ -1362,6 +1365,7 @@ static void test_prepare_insert_update()
for (cur_query= testcase; *cur_query; cur_query++)
{
+ char query[MAX_TEST_QUERY_LENGTH];
printf("\nRunning query: %s", *cur_query);
strmov(query, *cur_query);
stmt= mysql_simple_prepare(mysql, query);
@@ -1396,6 +1400,7 @@ static void test_prepare_simple()
{
MYSQL_STMT *stmt;
int rc;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_prepare_simple");
@@ -1466,6 +1471,7 @@ static void test_prepare_field_result()
MYSQL_STMT *stmt;
MYSQL_RES *result;
int rc;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_prepare_field_result");
@@ -1517,6 +1523,7 @@ static void test_prepare_syntax()
{
MYSQL_STMT *stmt;
int rc;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_prepare_syntax");
@@ -1558,6 +1565,7 @@ static void test_prepare()
my_bool is_null[7];
char llbuf[22];
MYSQL_BIND bind[7];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_prepare");
@@ -1731,6 +1739,7 @@ static void test_double_compare()
MYSQL_RES *result;
MYSQL_BIND bind[3];
ulong length[3];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_double_compare");
@@ -1813,6 +1822,7 @@ static void test_null()
uint nData;
MYSQL_BIND bind[2];
my_bool is_null[2];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_null");
@@ -1959,6 +1969,7 @@ static void test_ps_null_param()
/* Execute several queries, all returning NULL in result. */
for(cur_query= queries; *cur_query; cur_query++)
{
+ char query[MAX_TEST_QUERY_LENGTH];
strmov(query, *cur_query);
stmt= mysql_simple_prepare(mysql, query);
check_stmt(stmt);
@@ -1990,6 +2001,7 @@ static void test_fetch_null()
MYSQL_BIND bind[11];
ulong length[11];
my_bool is_null[11];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_fetch_null");
@@ -2218,6 +2230,7 @@ static void test_select()
int nData= 1;
MYSQL_BIND bind[2];
ulong length[2];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_select");
@@ -2289,6 +2302,7 @@ static void test_ps_conj_select()
int32 int_data;
char str_data[32];
unsigned long str_length;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_ps_conj_select");
rc= mysql_query(mysql, "drop table if exists t1");
@@ -2346,6 +2360,7 @@ static void test_bug1115()
MYSQL_BIND bind[1];
ulong length[1];
char szData[11];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_bug1115");
@@ -2457,6 +2472,7 @@ static void test_bug1180()
MYSQL_BIND bind[1];
ulong length[1];
char szData[11];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_select_bug");
@@ -2547,6 +2563,7 @@ static void test_bug1644()
int num;
my_bool isnull;
int rc, i;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_bug1644");
@@ -2646,6 +2663,7 @@ static void test_select_show()
{
MYSQL_STMT *stmt;
int rc;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_select_show");
@@ -2714,6 +2732,7 @@ static void test_simple_update()
MYSQL_RES *result;
MYSQL_BIND bind[2];
ulong length[2];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_simple_update");
@@ -2791,6 +2810,7 @@ static void test_long_data()
char *data= NullS;
MYSQL_RES *result;
MYSQL_BIND bind[3];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_long_data");
@@ -2877,6 +2897,7 @@ static void test_long_data_str()
MYSQL_RES *result;
MYSQL_BIND bind[2];
my_bool is_null[2];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_long_data_str");
@@ -2969,6 +2990,7 @@ static void test_long_data_str1()
MYSQL_RES *result;
MYSQL_BIND bind[2];
MYSQL_FIELD *field;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_long_data_str1");
@@ -3124,6 +3146,7 @@ static void test_long_data_bin()
long length;
MYSQL_RES *result;
MYSQL_BIND bind[2];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_long_data_bin");
@@ -3203,6 +3226,7 @@ static void test_simple_delete()
MYSQL_RES *result;
MYSQL_BIND bind[2];
ulong length[2];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_simple_delete");
@@ -3285,6 +3309,7 @@ static void test_update()
MYSQL_RES *result;
MYSQL_BIND bind[2];
ulong length[2];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_update");
@@ -3381,6 +3406,7 @@ static void test_prepare_noparam()
MYSQL_STMT *stmt;
int rc;
MYSQL_RES *result;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_prepare_noparam");
@@ -4237,6 +4263,7 @@ static void test_prepare_ext()
short sData= 10;
longlong bData= 20;
MYSQL_BIND bind[6];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_prepare_ext");
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_ext");
@@ -4624,6 +4651,7 @@ static void test_stmt_close()
MYSQL_RES *result;
unsigned int count;
int rc;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_stmt_close");
@@ -5270,6 +5298,7 @@ static void test_manual_sample()
ulonglong affected_rows;
MYSQL_BIND bind[3];
my_bool is_null;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_manual_sample");
@@ -5624,6 +5653,7 @@ static void test_prepare_multi_statements()
{
MYSQL *mysql_local;
MYSQL_STMT *stmt;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_prepare_multi_statements");
if (!(mysql_local= mysql_init(NULL)))
@@ -5841,6 +5871,7 @@ static void test_store_result2()
int nData;
ulong length;
MYSQL_BIND bind[1];
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_store_result2");
@@ -7120,6 +7151,7 @@ static void test_set_option()
static void test_prepare_grant()
{
int rc;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_prepare_grant");
@@ -8592,6 +8624,7 @@ static void test_sqlmode()
MYSQL_BIND bind[2];
char c1[5], c2[5];
int rc;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_sqlmode");
@@ -8735,6 +8768,7 @@ static void test_ts()
ulong length;
int rc, field_count;
char name;
+ char query[MAX_TEST_QUERY_LENGTH];
myheader("test_ts");
@@ -15019,6 +15053,65 @@ static void test_bug20152()
}
}
+/* Bug#15752 "Lost connection to MySQL server when calling a SP from C API" */
+
+static void test_bug15752()
+{
+ MYSQL mysql_local;
+ int rc, i;
+ const int ITERATION_COUNT= 100;
+ char *query= "CALL p1()";
+
+ myheader("test_bug15752");
+
+ rc= mysql_query(mysql, "drop procedure if exists p1");
+ myquery(rc);
+ rc= mysql_query(mysql, "create procedure p1() select 1");
+ myquery(rc);
+
+ mysql_init(&mysql_local);
+ if (! mysql_real_connect(&mysql_local, opt_host, opt_user,
+ opt_password, current_db, opt_port,
+ opt_unix_socket,
+ CLIENT_MULTI_STATEMENTS|CLIENT_MULTI_RESULTS))
+ {
+ printf("Unable connect to MySQL server: %s\n", mysql_error(&mysql_local));
+ DIE_UNLESS(0);
+ }
+ rc= mysql_real_query(&mysql_local, query, strlen(query));
+ myquery(rc);
+ mysql_free_result(mysql_store_result(&mysql_local));
+
+ rc= mysql_real_query(&mysql_local, query, strlen(query));
+ DIE_UNLESS(rc && mysql_errno(&mysql_local) == CR_COMMANDS_OUT_OF_SYNC);
+
+ if (! opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(&mysql_local));
+
+ /* Check some other commands too */
+
+ DIE_UNLESS(mysql_next_result(&mysql_local) == 0);
+ mysql_free_result(mysql_store_result(&mysql_local));
+ DIE_UNLESS(mysql_next_result(&mysql_local) == -1);
+
+ /* The second problem is not reproducible: add the test case */
+ for (i = 0; i < ITERATION_COUNT; i++)
+ {
+ if (mysql_real_query(&mysql_local, query, strlen(query)))
+ {
+ printf("\ni=%d %s failed: %s\n", i, query, mysql_error(&mysql_local));
+ break;
+ }
+ mysql_free_result(mysql_store_result(&mysql_local));
+ DIE_UNLESS(mysql_next_result(&mysql_local) == 0);
+ mysql_free_result(mysql_store_result(&mysql_local));
+ DIE_UNLESS(mysql_next_result(&mysql_local) == -1);
+
+ }
+ mysql_close(&mysql_local);
+ rc= mysql_query(mysql, "drop procedure p1");
+ myquery(rc);
+}
/*
Read and parse arguments and MySQL options from my.cnf
@@ -15287,7 +15380,8 @@ static struct my_tests_st my_tests[]= {
{ "test_bug20152", test_bug20152 },
{ "test_bug14169", test_bug14169 },
{ "test_bug17667", test_bug17667 },
- { "test_bug19671", test_bug19671},
+ { "test_bug19671", test_bug19671 },
+ { "test_bug15752", test_bug15752 },
{ 0, 0 }
};