Details
-
Bug
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
2.1
-
None
-
None
-
All
Description
There is a sequence of operations that can cause the client to hang when working with prepared statements. It only happens when 1) using stored procedures to return multiple result sets, 2) when an error occurs in the second or subsequent result set in the procedure, 3) when the statement is then re-used, and 4) when mysql_stmt_free_result() is called between receiving the error and reusing the statement. I think that the error is on line 1886 of my_stmt.c, but am not totally sure. (Perhaps need a line inserted at around 1890 of my_stmt.c to update the state once an error is detected.)
To reproduce, first need to setup the database:
create table test (KeyVal int not null primary key);
|
insert into test (KeyVal) values (1);
|
delimiter //
|
create procedure TestProc()
|
begin
|
select * from Test;
|
insert into Test (KeyVal) values (1);
|
end//
|
delimiter ;
|
When this stored proc is run, it will return a two result sets, but with an error value in the second one.
The C code side is:
char sQuery[] = "call testproc";
|
 |
MYSQL* pSQL = mysql_init(nullptr);
|
mysql_real_connect(pSQL, "127.0.0.1", "user", "password", "db", 0, nullptr, 0));
|
MYSQL_STMT* pStmt = mysql_stmt_init(pSQL);
|
mysql_stmt_prepare(pStmt, sQuery, sizeof(sQuery) - 1));
|
mysql_stmt_execute(pStmt);
|
mysql_stmt_next_result(pStmt); // Returns 1062 error for duplicate keys. stmt is in MYSQL_STMT_WAITING_USE_OR_STORE state on return from this function. This seems to be incorrect.
|
mysql_stmt_free_result(pStmt); // Moves the stmt into the MYSQL_STMT_USER_FETCHING state.
|
mysql_stmt_execute(pStmt); // This hangs. It is waiting for the server to send a result set, but the server has already sent an error code.
|
After writing the above, I did some additional testing, and everything seems to work if I remove the mysql_stmt_free_result() call. However, the behavior is inconsistent between when an error occurs in the first result set and when it occurs in a subsequent result set. (See line 1506 of my_stmt.c. If an error is returned by the first result set, the stmt is put into the MYSQL_STMT_PREPARED state.) There is another inconsistency there, too. When an error occurs in the first result set, stmt->upsert_status.affected_rows gets updated before returning the error code. In mysql_stmt_next_result(), this happens afterwards.
Update:
I have tested a fix. Inserting the following line at line 1892 in my_stmt.c fixes the problem:
stmt->state= MYSQL_STMT_PREPARED;
|