mirror of
https://github.com/MariaDB/server.git
synced 2025-01-28 01:34:17 +01:00
Recommit of bug 43560 after merge with mysql-5.1-bugteam
This commit is contained in:
parent
0130162452
commit
059dba14b7
3 changed files with 173 additions and 38 deletions
|
@ -924,6 +924,7 @@ void end_server(MYSQL *mysql)
|
|||
vio_delete(mysql->net.vio);
|
||||
reset_sigpipe(mysql);
|
||||
mysql->net.vio= 0; /* Marker */
|
||||
mysql_prune_stmt_list(mysql);
|
||||
}
|
||||
net_end(&mysql->net);
|
||||
free_old_query(mysql);
|
||||
|
@ -2526,30 +2527,9 @@ my_bool mysql_reconnect(MYSQL *mysql)
|
|||
tmp_mysql.reconnect= 1;
|
||||
tmp_mysql.free_me= mysql->free_me;
|
||||
|
||||
/*
|
||||
For each stmt in mysql->stmts, move it to tmp_mysql if it is
|
||||
in state MYSQL_STMT_INIT_DONE, otherwise close it.
|
||||
*/
|
||||
{
|
||||
LIST *element= mysql->stmts;
|
||||
for (; element; element= element->next)
|
||||
{
|
||||
MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
|
||||
if (stmt->state != MYSQL_STMT_INIT_DONE)
|
||||
{
|
||||
stmt->mysql= 0;
|
||||
stmt->last_errno= CR_SERVER_LOST;
|
||||
strmov(stmt->last_error, ER(CR_SERVER_LOST));
|
||||
strmov(stmt->sqlstate, unknown_sqlstate);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_mysql.stmts= list_add(tmp_mysql.stmts, &stmt->list);
|
||||
}
|
||||
/* No need to call list_delete for statement here */
|
||||
}
|
||||
mysql->stmts= NULL;
|
||||
}
|
||||
/* Move prepared statements (if any) over to the new mysql object */
|
||||
tmp_mysql.stmts= mysql->stmts;
|
||||
mysql->stmts= 0;
|
||||
|
||||
/* Don't free options as these are now used in tmp_mysql */
|
||||
bzero((char*) &mysql->options,sizeof(mysql->options));
|
||||
|
@ -2639,6 +2619,46 @@ static void mysql_close_free(MYSQL *mysql)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
For use when the connection to the server has been lost (in which case
|
||||
the server has discarded all information about prepared statements
|
||||
associated with the connection).
|
||||
|
||||
Mark all statements in mysql->stmts by setting stmt->mysql= 0 if the
|
||||
statement has transitioned beyond the MYSQL_STMT_INIT_DONE state, and
|
||||
unlink the statement from the mysql->stmts list.
|
||||
|
||||
The remaining pruned list of statements (if any) is kept in mysql->stmts.
|
||||
|
||||
@param mysql pointer to the MYSQL object
|
||||
|
||||
@return none
|
||||
*/
|
||||
void mysql_prune_stmt_list(MYSQL *mysql)
|
||||
{
|
||||
LIST *element= mysql->stmts;
|
||||
LIST *pruned_list= 0;
|
||||
|
||||
for (; element; element= element->next)
|
||||
{
|
||||
MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
|
||||
if (stmt->state != MYSQL_STMT_INIT_DONE)
|
||||
{
|
||||
stmt->mysql= 0;
|
||||
stmt->last_errno= CR_SERVER_LOST;
|
||||
strmov(stmt->last_error, ER(CR_SERVER_LOST));
|
||||
strmov(stmt->sqlstate, unknown_sqlstate);
|
||||
}
|
||||
else
|
||||
{
|
||||
pruned_list= list_add(pruned_list, element);
|
||||
}
|
||||
}
|
||||
|
||||
mysql->stmts= pruned_list;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Clear connection pointer of every statement: this is necessary
|
||||
to give error on attempt to use a prepared statement of closed
|
||||
|
|
|
@ -2461,6 +2461,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
|
|||
|
||||
stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end);
|
||||
|
||||
/* Close connection socket; for use with client testing (Bug#43560). */
|
||||
DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio););
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ if (!opt_silent) \
|
|||
|
||||
static void print_error(const char *msg);
|
||||
static void print_st_error(MYSQL_STMT *stmt, const char *msg);
|
||||
static void client_disconnect(void);
|
||||
static void client_disconnect(MYSQL* mysql, my_bool drop_db);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -271,10 +271,20 @@ mysql_simple_prepare(MYSQL *mysql_arg, const char *query)
|
|||
}
|
||||
|
||||
|
||||
/* Connect to the server */
|
||||
/**
|
||||
Connect to the server with options given by arguments to this application,
|
||||
stored in global variables opt_host, opt_user, opt_password, opt_db,
|
||||
opt_port and opt_unix_socket.
|
||||
|
||||
static void client_connect(ulong flag)
|
||||
@param flag[in] client_flag passed on to mysql_real_connect
|
||||
@param protocol[in] MYSQL_PROTOCOL_* to use for this connection
|
||||
@param auto_reconnect[in] set to 1 for auto reconnect
|
||||
|
||||
@return pointer to initialized and connected MYSQL object
|
||||
*/
|
||||
static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect)
|
||||
{
|
||||
MYSQL* mysql;
|
||||
int rc;
|
||||
static char query[MAX_TEST_QUERY_LENGTH];
|
||||
myheader_r("client_connect");
|
||||
|
@ -291,6 +301,7 @@ static void client_connect(ulong flag)
|
|||
}
|
||||
/* enable local infile, in non-binary builds often disabled by default */
|
||||
mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0);
|
||||
mysql_options(mysql, MYSQL_OPT_PROTOCOL, &protocol);
|
||||
|
||||
if (!(mysql_real_connect(mysql, opt_host, opt_user,
|
||||
opt_password, opt_db ? opt_db:"test", opt_port,
|
||||
|
@ -302,7 +313,7 @@ static void client_connect(ulong flag)
|
|||
fprintf(stdout, "\n Check the connection options using --help or -?\n");
|
||||
exit(1);
|
||||
}
|
||||
mysql->reconnect= 1;
|
||||
mysql->reconnect= auto_reconnect;
|
||||
|
||||
if (!opt_silent)
|
||||
fprintf(stdout, "OK");
|
||||
|
@ -329,12 +340,14 @@ static void client_connect(ulong flag)
|
|||
|
||||
if (!opt_silent)
|
||||
fprintf(stdout, "OK");
|
||||
|
||||
return mysql;
|
||||
}
|
||||
|
||||
|
||||
/* Close the connection */
|
||||
|
||||
static void client_disconnect()
|
||||
static void client_disconnect(MYSQL* mysql, my_bool drop_db)
|
||||
{
|
||||
static char query[MAX_TEST_QUERY_LENGTH];
|
||||
|
||||
|
@ -342,13 +355,16 @@ static void client_disconnect()
|
|||
|
||||
if (mysql)
|
||||
{
|
||||
if (!opt_silent)
|
||||
fprintf(stdout, "\n dropping the test database '%s' ...", current_db);
|
||||
strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS);
|
||||
if (drop_db)
|
||||
{
|
||||
if (!opt_silent)
|
||||
fprintf(stdout, "\n dropping the test database '%s' ...", current_db);
|
||||
strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS);
|
||||
|
||||
mysql_query(mysql, query);
|
||||
if (!opt_silent)
|
||||
fprintf(stdout, "OK");
|
||||
mysql_query(mysql, query);
|
||||
if (!opt_silent)
|
||||
fprintf(stdout, "OK");
|
||||
}
|
||||
|
||||
if (!opt_silent)
|
||||
fprintf(stdout, "\n closing the connection ...");
|
||||
|
@ -17712,6 +17728,100 @@ static void test_bug40365(void)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Subtest for Bug#43560. Verifies that a loss of connection on the server side
|
||||
is handled well by the mysql_stmt_execute() call, i.e., no SIGSEGV due to
|
||||
a vio socket that is cleared upon closed connection.
|
||||
|
||||
Assumes the presence of the close_conn_after_stmt_execute debug feature in
|
||||
the server. Verifies that it is connected to a debug server before proceeding
|
||||
with the test.
|
||||
*/
|
||||
static void test_bug43560(void)
|
||||
{
|
||||
MYSQL* conn;
|
||||
uint rc;
|
||||
MYSQL_STMT *stmt= 0;
|
||||
MYSQL_BIND bind;
|
||||
my_bool is_null= 0;
|
||||
const uint BUFSIZE= 256;
|
||||
char buffer[BUFSIZE];
|
||||
const char* values[] = {"eins", "zwei", "drei", "viele", NULL};
|
||||
const char insert_str[] = "INSERT INTO t1 (c2) VALUES (?)";
|
||||
unsigned long length;
|
||||
|
||||
DBUG_ENTER("test_bug43560");
|
||||
myheader("test_bug43560");
|
||||
|
||||
/* Make sure we only run against a debug server. */
|
||||
if (!strstr(mysql->server_version, "debug"))
|
||||
{
|
||||
fprintf(stdout, "Skipping test_bug43560: server not DEBUG version\n");
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
Set up a separate connection for this test to avoid messing up the
|
||||
general MYSQL object used in other subtests. Use TCP protocol to avoid
|
||||
problems with the buffer semantics of AF_UNIX, and turn off auto reconnect.
|
||||
*/
|
||||
conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0);
|
||||
|
||||
rc= mysql_query(conn, "DROP TABLE IF EXISTS t1");
|
||||
myquery(rc);
|
||||
rc= mysql_query(conn,
|
||||
"CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 CHAR(10))");
|
||||
myquery(rc);
|
||||
|
||||
stmt= mysql_stmt_init(conn);
|
||||
check_stmt(stmt);
|
||||
rc= mysql_stmt_prepare(stmt, insert_str, strlen(insert_str));
|
||||
check_execute(stmt, rc);
|
||||
|
||||
bind.buffer_type= MYSQL_TYPE_STRING;
|
||||
bind.buffer_length= BUFSIZE;
|
||||
bind.buffer= buffer;
|
||||
bind.is_null= &is_null;
|
||||
bind.length= &length;
|
||||
rc= mysql_stmt_bind_param(stmt, &bind);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
/* First execute; should succeed. */
|
||||
strncpy(buffer, values[0], BUFSIZE);
|
||||
length= strlen(buffer);
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
/*
|
||||
Set up the server to close this session's server-side socket after
|
||||
next execution of prep statement.
|
||||
*/
|
||||
rc= mysql_query(conn,"SET SESSION debug='+d,close_conn_after_stmt_execute'");
|
||||
myquery(rc);
|
||||
|
||||
/* Second execute; should fail due to socket closed during execution. */
|
||||
strncpy(buffer, values[1], BUFSIZE);
|
||||
length= strlen(buffer);
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
DIE_UNLESS(rc && mysql_stmt_errno(stmt) == CR_SERVER_LOST);
|
||||
|
||||
/*
|
||||
Third execute; should fail (connection already closed), or SIGSEGV in
|
||||
case of a Bug#43560 type regression in which case the whole test fails.
|
||||
*/
|
||||
strncpy(buffer, values[2], BUFSIZE);
|
||||
length= strlen(buffer);
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
DIE_UNLESS(rc && mysql_stmt_errno(stmt) == CR_SERVER_LOST);
|
||||
|
||||
client_disconnect(conn, 0);
|
||||
rc= mysql_query(mysql, "DROP TABLE t1");
|
||||
myquery(rc);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Bug#36326: nested transaction and select
|
||||
*/
|
||||
|
@ -18140,6 +18250,7 @@ static struct my_tests_st my_tests[]= {
|
|||
{ "test_wl4166_2", test_wl4166_2 },
|
||||
{ "test_bug38486", test_bug38486 },
|
||||
{ "test_bug40365", test_bug40365 },
|
||||
{ "test_bug43560", test_bug43560 },
|
||||
#ifdef HAVE_QUERY_CACHE
|
||||
{ "test_bug36326", test_bug36326 },
|
||||
#endif
|
||||
|
@ -18268,7 +18379,8 @@ int main(int argc, char **argv)
|
|||
(char**) embedded_server_groups))
|
||||
DIE("Can't initialize MySQL server");
|
||||
|
||||
client_connect(0); /* connect to server */
|
||||
/* connect to server with no flags, default protocol, auto reconnect true */
|
||||
mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1);
|
||||
|
||||
total_time= 0;
|
||||
for (iter_count= 1; iter_count <= opt_count; iter_count++)
|
||||
|
@ -18298,7 +18410,7 @@ int main(int argc, char **argv)
|
|||
fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv);
|
||||
fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n",
|
||||
my_progname);
|
||||
client_disconnect();
|
||||
client_disconnect(mysql, 1);
|
||||
free_defaults(defaults_argv);
|
||||
exit(1);
|
||||
}
|
||||
|
@ -18311,7 +18423,7 @@ int main(int argc, char **argv)
|
|||
/* End of tests */
|
||||
}
|
||||
|
||||
client_disconnect(); /* disconnect from server */
|
||||
client_disconnect(mysql, 1); /* disconnect from server */
|
||||
|
||||
free_defaults(defaults_argv);
|
||||
print_test_output();
|
||||
|
|
Loading…
Add table
Reference in a new issue