Skip to content

Commit 475330b

Browse files
committed
Fix processing of unfetched multi result sets
Do not use mysql_use_result() when throwing away unfetched result sets. Documentation for this function says: When using mysql_use_result(), you must execute mysql_fetch_row() until a NULL value is returned, otherwise, the unfetched rows are returned as part of the result set for your next query. The C API gives the error Commands out of sync; you can't run this command now if you forget to do this! So use mysql_store_result() instead which is safe as it does not require to call mysql_fetch_row() for each row in result set. Also correctly check for errors returned by mysql_store_result() and rethrow them to DBI.
1 parent 25aad51 commit 475330b

File tree

1 file changed

+35
-8
lines changed

1 file changed

+35
-8
lines changed

dbdimp.c

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2551,9 +2551,9 @@ IV mariadb_db_do6(SV *dbh, imp_dbh_t *imp_dbh, SV *statement_sv, SV *attribs, I3
25512551
bool disable_fallback_for_server_prepare = FALSE;
25522552
MYSQL_STMT *stmt = NULL;
25532553
MYSQL_BIND *bind = NULL;
2554-
MYSQL_RES *res;
25552554
STRLEN blen;
25562555
unsigned long int num_params;
2556+
unsigned int error;
25572557

25582558
ASYNC_CHECK_RETURN(dbh, -2);
25592559

@@ -2642,11 +2642,33 @@ IV mariadb_db_do6(SV *dbh, imp_dbh_t *imp_dbh, SV *statement_sv, SV *attribs, I3
26422642
imp_dbh->async_query_in_flight = imp_dbh;
26432643
}
26442644

2645-
while (mysql_next_result(imp_dbh->pmysql) == 0)
2645+
while ((next_result_rc = mysql_next_result(imp_dbh->pmysql)) == 0)
2646+
{
2647+
result = mysql_store_result(imp_dbh->pmysql);
2648+
if (!result)
2649+
{
2650+
if (mysql_errno(imp_dbh->pmysql))
2651+
{
2652+
mariadb_dr_do_error(dbh, mysql_errno(imp_dbh->pmysql), mysql_error(imp_dbh->pmysql), mysql_sqlstate(imp_dbh->pmysql));
2653+
return -2;
2654+
}
2655+
}
2656+
if (result)
2657+
{
2658+
mysql_free_result(result);
2659+
result = NULL;
2660+
}
2661+
}
2662+
2663+
if (next_result_rc > 0)
26462664
{
2647-
res = mysql_use_result(imp_dbh->pmysql);
2648-
if (res)
2649-
mysql_free_result(res);
2665+
/* This is error for previous unfetched result ret. So do not report server errors to caller which is expecting new result set. */
2666+
error = mysql_errno(imp_dbh->pmysql);
2667+
if (error == CR_COMMANDS_OUT_OF_SYNC || error == CR_OUT_OF_MEMORY || error == CR_SERVER_GONE_ERROR || error == CR_SERVER_LOST || error == CR_UNKNOWN_ERROR)
2668+
{
2669+
mariadb_dr_do_error(dbh, mysql_errno(imp_dbh->pmysql), mysql_error(imp_dbh->pmysql), mysql_sqlstate(imp_dbh->pmysql));
2670+
return -2;
2671+
}
26502672
}
26512673

26522674
if (use_server_side_prepare)
@@ -2804,7 +2826,12 @@ IV mariadb_db_do6(SV *dbh, imp_dbh_t *imp_dbh, SV *statement_sv, SV *attribs, I3
28042826
/* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
28052827
while ((next_result_rc = mysql_next_result(imp_dbh->pmysql)) == 0)
28062828
{
2807-
result = mysql_use_result(imp_dbh->pmysql);
2829+
result = mysql_store_result(imp_dbh->pmysql);
2830+
if (mysql_errno(imp_dbh->pmysql))
2831+
{
2832+
next_result_rc = 1;
2833+
break;
2834+
}
28082835
if (!result) /* Next statement without result set, new insert id */
28092836
imp_dbh->insertid = mysql_insert_id(imp_dbh->pmysql);
28102837
if (result)
@@ -3967,10 +3994,10 @@ static int mariadb_st_free_result_sets (SV * sth, imp_sth_t * imp_sth)
39673994

39683995
if (next_result_rc == 0)
39693996
{
3970-
if (!(imp_sth->result = mysql_use_result(imp_dbh->pmysql)))
3997+
if (!(imp_sth->result = mysql_store_result(imp_dbh->pmysql)))
39713998
{
39723999
/* Check for possible error */
3973-
if (mysql_field_count(imp_dbh->pmysql))
4000+
if (mysql_errno(imp_dbh->pmysql))
39744001
{
39754002
if (DBIc_TRACE_LEVEL(imp_xxh) >= 2)
39764003
PerlIO_printf(DBIc_LOGPIO(imp_xxh), "\t<- mariadb_st_free_result_sets ERROR: %s\n",

0 commit comments

Comments
 (0)