Description:
The mysql_fetch_row_nonblocking() function is intended to be called multiple times. On the last time (once all rows have been fetched) it is supposed to set the row pointer to null. Unfortunately it also sets the errno for the connection to CR_COMMANDS_OUT_OF_SYNC.
Note that this occurs when using mysql_use_result but not when using mysql_store_result[_nonblocking].
How to repeat:
To repeat this I made some changes to the mysql_client_test.c, replacing the call to mysql_store_result_nonblocking with a call to mysql_use_result and then adding an additional call to mysql_fetch_row_nonblocking() that I expect to set `row` to null. If I comment out the check for errno == 0 the test succeeds. Once I add the suggested fix the test also passes.
```
diff --git a/testclients/mysql_client_test.cc b/testclients/mysql_client_test.cc
index 2c45d41da89..0653c691f8e 100644
--- a/testclients/mysql_client_test.cc
+++ b/testclients/mysql_client_test.cc
@@ -20225,18 +20225,7 @@ static void test_wl11381() {
} else {
fprintf(stdout, "\n mysql_real_query_nonblocking() passed");
}
- status = mysql_store_result_nonblocking(mysql_local, &result);
- /* do some other task */
- perform_arithmatic();
- while (status == NET_ASYNC_NOT_READY) {
- status = mysql_store_result_nonblocking(mysql_local, &result);
- }
- if (!result) {
- fprintf(stdout, "\n mysql_store_result_nonblocking() fetched 0 records");
- exit(1);
- } else {
- fprintf(stdout, "\n mysql_store_result_nonblocking() passed");
- }
+ result = mysql_use_result(mysql_local);
row = mysql_fetch_row(result);
DIE_UNLESS(strcmp(row[0], "10") == 0);
@@ -20263,6 +20252,14 @@ static void test_wl11381() {
fprintf(stdout, "\n mysql_fetch_row_nonblocking() passed");
}
+ while ((status = mysql_fetch_row_nonblocking(result, &row)) == NET_ASYNC_NOT_READY) {
+ /* do some other task */
+ perform_arithmatic();
+ }
+
+ DIE_UNLESS(row == nullptr);
+ DIE_UNLESS(mysql_errno(mysql_local) == 0);
+
while ((status = mysql_free_result_nonblocking(result)) != NET_ASYNC_COMPLETE)
;
fprintf(stdout, "\n mysql_free_result_nonblocking() passed");
```
Suggested fix:
diff --git a/sql-common/client.cc b/sql-common/client.cc
index fd36e9950cf..b5575af69ba 100644
--- a/sql-common/client.cc
+++ b/sql-common/client.cc
@@ -7538,11 +7538,13 @@ net_async_status STDCALL mysql_fetch_row_nonblocking(MYSQL_RES *res,
goto end;
}
}
+ else {
+ set_mysql_error(mysql,
+ res->unbuffered_fetch_cancelled ? CR_FETCH_CANCELED
+ : CR_COMMANDS_OUT_OF_SYNC,
+ unknown_sqlstate);
+ }
- set_mysql_error(mysql,
- res->unbuffered_fetch_cancelled ? CR_FETCH_CANCELED
- : CR_COMMANDS_OUT_OF_SYNC,
- unknown_sqlstate);
DBUG_PRINT("info", ("end of data"));
res->eof = true;
mysql->status = MYSQL_STATUS_READY;
Description: The mysql_fetch_row_nonblocking() function is intended to be called multiple times. On the last time (once all rows have been fetched) it is supposed to set the row pointer to null. Unfortunately it also sets the errno for the connection to CR_COMMANDS_OUT_OF_SYNC. Note that this occurs when using mysql_use_result but not when using mysql_store_result[_nonblocking]. How to repeat: To repeat this I made some changes to the mysql_client_test.c, replacing the call to mysql_store_result_nonblocking with a call to mysql_use_result and then adding an additional call to mysql_fetch_row_nonblocking() that I expect to set `row` to null. If I comment out the check for errno == 0 the test succeeds. Once I add the suggested fix the test also passes. ``` diff --git a/testclients/mysql_client_test.cc b/testclients/mysql_client_test.cc index 2c45d41da89..0653c691f8e 100644 --- a/testclients/mysql_client_test.cc +++ b/testclients/mysql_client_test.cc @@ -20225,18 +20225,7 @@ static void test_wl11381() { } else { fprintf(stdout, "\n mysql_real_query_nonblocking() passed"); } - status = mysql_store_result_nonblocking(mysql_local, &result); - /* do some other task */ - perform_arithmatic(); - while (status == NET_ASYNC_NOT_READY) { - status = mysql_store_result_nonblocking(mysql_local, &result); - } - if (!result) { - fprintf(stdout, "\n mysql_store_result_nonblocking() fetched 0 records"); - exit(1); - } else { - fprintf(stdout, "\n mysql_store_result_nonblocking() passed"); - } + result = mysql_use_result(mysql_local); row = mysql_fetch_row(result); DIE_UNLESS(strcmp(row[0], "10") == 0); @@ -20263,6 +20252,14 @@ static void test_wl11381() { fprintf(stdout, "\n mysql_fetch_row_nonblocking() passed"); } + while ((status = mysql_fetch_row_nonblocking(result, &row)) == NET_ASYNC_NOT_READY) { + /* do some other task */ + perform_arithmatic(); + } + + DIE_UNLESS(row == nullptr); + DIE_UNLESS(mysql_errno(mysql_local) == 0); + while ((status = mysql_free_result_nonblocking(result)) != NET_ASYNC_COMPLETE) ; fprintf(stdout, "\n mysql_free_result_nonblocking() passed"); ``` Suggested fix: diff --git a/sql-common/client.cc b/sql-common/client.cc index fd36e9950cf..b5575af69ba 100644 --- a/sql-common/client.cc +++ b/sql-common/client.cc @@ -7538,11 +7538,13 @@ net_async_status STDCALL mysql_fetch_row_nonblocking(MYSQL_RES *res, goto end; } } + else { + set_mysql_error(mysql, + res->unbuffered_fetch_cancelled ? CR_FETCH_CANCELED + : CR_COMMANDS_OUT_OF_SYNC, + unknown_sqlstate); + } - set_mysql_error(mysql, - res->unbuffered_fetch_cancelled ? CR_FETCH_CANCELED - : CR_COMMANDS_OUT_OF_SYNC, - unknown_sqlstate); DBUG_PRINT("info", ("end of data")); res->eof = true; mysql->status = MYSQL_STATUS_READY;