diff options
author | unknown <msvensson@neptunus.(none)> | 2007-01-16 13:39:42 +0100 |
---|---|---|
committer | unknown <msvensson@neptunus.(none)> | 2007-01-16 13:39:42 +0100 |
commit | 7b965030418e9460c9f0324cdea0f0decd9686ee (patch) | |
tree | c33a821cc43b96773ccb3649535c3122cf5a87b9 | |
parent | 89d106c1a4efad141e7850373335482ad46aeec5 (diff) | |
download | mariadb-git-7b965030418e9460c9f0324cdea0f0decd9686ee.tar.gz |
Bug#15518 Reusing a stmt that has failed during prepare does not clear error
- Always reset error when calling mysql_stmt_prepare a second time
- Set stmt->state to MYSQL_STMT_INIT_DONE before closing prepared stmt in server.
- Add test to mysql_client_test
- Remove mysql_stmt_close in mysqltest after each query
- Close all open statements in mysqltest if disable_ps_protocol is called.
client/mysqltest.c:
Don't close the statement after each query - reprepare it in next query.
When "disable_ps_protocol" is issued make sure to close all open
statements. Otherwise the test for @@max_prepared_statements fails. But we
also get a test that the statements that are open can be closed and reopened
in the middle of the tests.
libmysql/libmysql.c:
Reset the last error every time mysql_stmt_prepare is called.
Set state to MYSQL_STMT_INIT_DONE befoe closing it in the server. That way
we will always have right status regardless of wheter close fails or not.
tests/mysql_client_test.c:
Add testcase for bug15518, re-prepare a previously prepare statement that has failed
to prepare. Test also when connection to server has been lost inbetween.
Change all assert to DIE_UNLESS so we get printout of line and an error message
if it fails.
-rw-r--r-- | client/mysqltest.c | 25 | ||||
-rw-r--r-- | libmysql/libmysql.c | 14 | ||||
-rw-r--r-- | tests/mysql_client_test.c | 93 |
3 files changed, 117 insertions, 15 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c index 005f204d571..b163b5887e4 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -719,6 +719,20 @@ void close_connections() } +void close_statements() +{ + struct st_connection *con; + DBUG_ENTER("close_statements"); + for (con= connections; con < next_con; con++) + { + if (con->stmt) + mysql_stmt_close(con->stmt); + con->stmt= 0; + } + DBUG_VOID_RETURN; +} + + void close_files() { DBUG_ENTER("close_files"); @@ -2855,6 +2869,10 @@ void do_close_connection(struct st_command *command) } } #endif + if (next_con->stmt) + mysql_stmt_close(next_con->stmt); + next_con->stmt= 0; + mysql_close(&con->mysql); if (con->util_mysql) mysql_close(con->util_mysql); @@ -5050,10 +5068,7 @@ end: */ var_set_errno(mysql_stmt_errno(stmt)); -#ifndef BUG15518_FIXED - mysql_stmt_close(stmt); - cur_con->stmt= NULL; -#endif + DBUG_VOID_RETURN; } @@ -5838,6 +5853,8 @@ int main(int argc, char **argv) break; case Q_DISABLE_PS_PROTOCOL: ps_protocol_enabled= 0; + /* Close any open statements */ + close_statements(); break; case Q_ENABLE_PS_PROTOCOL: ps_protocol_enabled= ps_protocol; diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 6a592f64e49..a5dcb66f002 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -2038,6 +2038,13 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) DBUG_RETURN(1); } + /* + Reset the last error in any case: that would clear the statement + if the previous prepare failed. + */ + stmt->last_errno= 0; + stmt->last_error[0]= '\0'; + if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE) { /* This is second prepare with another statement */ @@ -2051,23 +2058,24 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) */ stmt->bind_param_done= stmt->bind_result_done= FALSE; stmt->param_count= stmt->field_count= 0; - stmt->last_errno= 0; - stmt->last_error[0]= '\0'; free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC)); int4store(buff, stmt->stmt_id); + /* + Close statement in server + If there was a 'use' result from another statement, or from mysql_use_result it won't be freed in mysql_stmt_free_result and we should get 'Commands out of sync' here. */ + stmt->state= MYSQL_STMT_INIT_DONE; if (stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt)) { set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, mysql->net.sqlstate); DBUG_RETURN(1); } - stmt->state= MYSQL_STMT_INIT_DONE; } if (stmt_command(mysql, COM_STMT_PREPARE, query, length, stmt)) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index aa993230a7f..22aa1e6ef21 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -11014,7 +11014,7 @@ static void test_view() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); rc= my_process_stmt_result(stmt); - assert(1 == rc); + DIE_UNLESS(1 == rc); } mysql_stmt_close(stmt); @@ -11057,7 +11057,7 @@ static void test_view_where() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); rc= my_process_stmt_result(stmt); - assert(4 == rc); + DIE_UNLESS(4 == rc); } mysql_stmt_close(stmt); @@ -11140,7 +11140,7 @@ static void test_view_2where() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); rc= my_process_stmt_result(stmt); - assert(0 == rc); + DIE_UNLESS(0 == rc); mysql_stmt_close(stmt); @@ -11193,7 +11193,7 @@ static void test_view_star() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); rc= my_process_stmt_result(stmt); - assert(0 == rc); + DIE_UNLESS(0 == rc); } mysql_stmt_close(stmt); @@ -11256,7 +11256,7 @@ static void test_view_insert() rc= mysql_stmt_execute(select_stmt); check_execute(select_stmt, rc); rowcount= (int)my_process_stmt_result(select_stmt); - assert((i+1) == rowcount); + DIE_UNLESS((i+1) == rowcount); } mysql_stmt_close(insert_stmt); mysql_stmt_close(select_stmt); @@ -11297,7 +11297,7 @@ static void test_left_join_view() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); rc= my_process_stmt_result(stmt); - assert(3 == rc); + DIE_UNLESS(3 == rc); } mysql_stmt_close(stmt); @@ -11373,7 +11373,7 @@ static void test_view_insert_fields() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); rc= my_process_stmt_result(stmt); - assert(1 == rc); + DIE_UNLESS(1 == rc); mysql_stmt_close(stmt); rc= mysql_query(mysql, "DROP VIEW v1"); @@ -12851,6 +12851,82 @@ static void test_bug7990() DIE_UNLESS(!mysql_errno(mysql)); } +/* + Bug #15518 - Reusing a stmt that has failed during prepare + does not clear error +*/ + +static void test_bug15518() +{ + MYSQL_STMT *stmt; + MYSQL* mysql1; + int rc; + myheader("test_bug15518"); + + mysql1= mysql_init(NULL); + + if (!mysql_real_connect(mysql1, opt_host, opt_user, opt_password, + opt_db ? opt_db : "test", opt_port, opt_unix_socket, + CLIENT_MULTI_STATEMENTS)) + { + fprintf(stderr, "Failed to connect to the database\n"); + DIE_UNLESS(0); + } + + stmt= mysql_stmt_init(mysql1); + + /* + The prepare of foo should fail with errno 1064 since + it's not a valid query + */ + rc= mysql_stmt_prepare(stmt, "foo", 3); + if (!opt_silent) + fprintf(stdout, "rc: %d, mysql_stmt_errno: %d, mysql_errno: %d\n", + rc, mysql_stmt_errno(stmt), mysql_errno(mysql1)); + DIE_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql1)); + + /* + Use the same stmt and reprepare with another query that + suceeds + */ + rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12); + if (!opt_silent) + fprintf(stdout, "rc: %d, mysql_stmt_errno: %d, mysql_errno: %d\n", + rc, mysql_stmt_errno(stmt), mysql_errno(mysql1)); + DIE_UNLESS(!rc || mysql_stmt_errno(stmt) || mysql_errno(mysql1)); + + mysql_stmt_close(stmt); + DIE_UNLESS(!mysql_errno(mysql1)); + + /* + part2, when connection to server has been closed + after first prepare + */ + stmt= mysql_stmt_init(mysql1); + rc= mysql_stmt_prepare(stmt, "foo", 3); + if (!opt_silent) + fprintf(stdout, "rc: %d, mysql_stmt_errno: %d, mysql_errno: %d\n", + rc, mysql_stmt_errno(stmt), mysql_errno(mysql1)); + DIE_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql1)); + + /* Close connection to server */ + mysql_close(mysql1); + + /* + Use the same stmt and reprepare with another query that + suceeds. The prepare should fail with error 2013 since + connection to server has been closed. + */ + rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12); + if (!opt_silent) + fprintf(stdout, "rc: %d, mysql_stmt_errno: %d\n", + rc, mysql_stmt_errno(stmt)); + DIE_UNLESS(rc && mysql_stmt_errno(stmt)); + + mysql_stmt_close(stmt); + DIE_UNLESS(mysql_errno(mysql1)); +} + static void test_view_sp_list_fields() { @@ -15009,7 +15085,7 @@ static void test_bug17667() } else { - assert(0==1); + DIE_UNLESS(0==1); } } @@ -15588,6 +15664,7 @@ static struct my_tests_st my_tests[]= { { "test_bug15752", test_bug15752 }, { "test_bug21206", test_bug21206 }, { "test_bug21726", test_bug21726 }, + { "test_bug15518", test_bug15518 }, { 0, 0 } }; |