diff options
-rw-r--r-- | libmysql/libmysql.c | 33 | ||||
-rw-r--r-- | tests/mysql_client_test.c | 104 |
2 files changed, 120 insertions, 17 deletions
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index e992c862537..3d8a2bebc75 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1273,6 +1273,7 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *, MYSQL_FIELD *field); #define RESET_LONG_DATA 2 #define RESET_STORE_RESULT 4 #define RESET_CLEAR_ERROR 8 +#define RESET_ALL_BUFFERS 16 static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags); @@ -4615,6 +4616,14 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) *mysql->unbuffered_fetch_owner= TRUE; mysql->status= MYSQL_STATUS_READY; } + if (flags & RESET_ALL_BUFFERS) + { + /* mysql_stmt_next_result will flush all pending + result sets + */ + while (mysql_more_results(mysql) && + mysql_stmt_next_result(stmt) == 0); + } } if (flags & RESET_SERVER_SIDE) { @@ -4679,27 +4688,18 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) { mysql->stmts= list_delete(mysql->stmts, &stmt->list); /* - Clear NET error state: if the following commands come through - successfully, connection will still be usable for other commands. + Clear NET error state: if the following commands come through + successfully, connection will still be usable for other commands. */ net_clear_error(&mysql->net); + if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE) { uchar buff[MYSQL_STMT_HEADER]; /* 4 bytes - stmt id */ - if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled) - mysql->unbuffered_fetch_owner= 0; - if (mysql->status != MYSQL_STATUS_READY) - { - /* - Flush result set of the connection. If it does not belong - to this statement, set a warning. - */ - (*mysql->methods->flush_use_result)(mysql, TRUE); - if (mysql->unbuffered_fetch_owner) - *mysql->unbuffered_fetch_owner= TRUE; - mysql->status= MYSQL_STATUS_READY; - } + if ((rc= reset_stmt_handle(stmt, RESET_ALL_BUFFERS | RESET_CLEAR_ERROR))) + return rc; + int4store(buff, stmt->stmt_id); if ((rc= stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt))) { @@ -4731,7 +4731,7 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt) /* Reset the client and server sides of the prepared statement */ DBUG_RETURN(reset_stmt_handle(stmt, RESET_SERVER_SIDE | RESET_LONG_DATA | - RESET_CLEAR_ERROR)); + RESET_ALL_BUFFERS | RESET_CLEAR_ERROR)); } /* @@ -4843,7 +4843,6 @@ int STDCALL mysql_next_result(MYSQL *mysql) DBUG_RETURN(-1); /* No more results */ } - int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt) { MYSQL *mysql= stmt->mysql; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 509e0e73777..b3bbebb2433 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -18749,6 +18749,109 @@ static void test_bug12337762() DBUG_VOID_RETURN; } +/* + MDEV-4603: mysql_stmt_reset doesn't clear + all result sets (from stored procedures). + This test requires also fix for MDEV-4604 +*/ +static void test_mdev4603() +{ + MYSQL *my; + MYSQL_STMT *stmt; + int i, rc; + int a[] = {10,20,30}; + MYSQL_BIND bind[3]; + + myheader("test_mdev4603"); + my= mysql_client_init(NULL); + + if (!mysql_real_connect(my, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_MULTI_RESULTS)) + DIE("mysql_real_connect failed"); + + /* 1st test: + use a procedure with out param + */ + rc= mysql_query(my, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE PROCEDURE p1(OUT p_out VARCHAR(19), IN p_in INT, INOUT p_inout INT)" + "BEGIN " + " SET p_in = 300, p_out := 'This is OUT param', p_inout = 200; " + " SELECT p_inout, p_in, substring(p_out, 9);" + "END"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + DIE_UNLESS(stmt != NULL); + + rc= mysql_stmt_prepare(stmt, "CALL P1(?,?,?)", 14); + DIE_UNLESS(rc == 0); + + DIE_UNLESS(mysql_stmt_param_count(stmt) == 3); + + memset(bind, 0, sizeof(MYSQL_BIND) * 3); + for (i=0; i < 3; i++) + { + bind[i].buffer= &a[i]; + bind[i].buffer_type= MYSQL_TYPE_LONG; + } + bind[0].buffer_type= MYSQL_TYPE_NULL; + rc= mysql_stmt_bind_param(stmt, bind); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_reset(stmt); + DIE_UNLESS(rc == 0); + + /*connection shouldn't be blocked now */ + + rc= mysql_query(mysql, "DROP PROCEDURE p1"); + myquery(rc); + + /* 2nd test: + reset all result sets */ + rc= mysql_query(my, "CREATE PROCEDURE p1() " + "BEGIN" + " SELECT 1,2,3 FROM DUAL;" + " SELECT 'foo' FROM DUAL;" + "END"); + myquery(rc); + + rc= mysql_stmt_prepare(stmt, "CALL P1()", 9); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_reset(stmt); + DIE_UNLESS(rc == 0); + + /* 3rd test: + mysql_stmt_close should also flush all pending + result sets + */ + + rc= mysql_stmt_prepare(stmt, "CALL P1()", 9); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(my, "DROP PROCEDURE p1"); + myquery(rc); + + mysql_close(my); +} /* BUG 11754979 - 46675: ON DUPLICATE KEY UPDATE AND UPDATECOUNT() POSSIBLY WRONG @@ -19289,6 +19392,7 @@ static struct my_tests_st my_tests[]= { { "test_bug57058", test_bug57058 }, { "test_bug56976", test_bug56976 }, { "test_mdev3885", test_mdev3885 }, + { "test_mdev4603", test_mdev4603 }, { "test_bug11766854", test_bug11766854 }, { "test_bug12337762", test_bug12337762 }, { "test_progress_reporting", test_progress_reporting }, |