From 236ed89eb2a91f2dce71516b3b53325a7fcb68f8 Mon Sep 17 00:00:00 2001 From: Robert Vollmer Date: Mon, 28 Nov 2022 11:59:19 +0100 Subject: [PATCH 1/4] Respect mariadb_use_result for async queries --- dbdimp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dbdimp.c b/dbdimp.c index 0f440892..7d4d88bb 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -6485,6 +6485,7 @@ my_ulonglong mariadb_db_async_result(SV* h, MYSQL_RES** resp) unsigned int num_fields; int htype; bool async_sth = FALSE; + bool use_mysql_use_result; if(! resp) { resp = &_res; @@ -6495,12 +6496,14 @@ my_ulonglong mariadb_db_async_result(SV* h, MYSQL_RES** resp) if(htype == DBIt_DB) { D_imp_dbh(h); dbh = imp_dbh; + use_mysql_use_result = imp_dbh->use_mysql_use_result; } else { D_imp_sth(h); D_imp_dbh_from_sth; dbh = imp_dbh; async_sth = imp_sth->is_async; retval = imp_sth->row_num; + use_mysql_use_result = imp_sth->use_mysql_use_result; } if(! dbh->async_query_in_flight) { @@ -6536,7 +6539,8 @@ my_ulonglong mariadb_db_async_result(SV* h, MYSQL_RES** resp) if (!mysql_read_query_result(svsock)) { - *resp= mysql_store_result(svsock); + *resp= use_mysql_use_result ? + mysql_use_result(svsock) : mysql_store_result(svsock); if (mysql_errno(svsock)) { From 556dab6b9e23d76d1990525af2014e0ca12beae9 Mon Sep 17 00:00:00 2001 From: Robert Vollmer Date: Mon, 28 Nov 2022 12:05:00 +0100 Subject: [PATCH 2/4] Fix Active attribute for mariadb_use_result mysql_num_rows() is 0 after mysql_use_result() until all results have been fetched, so we can't rely on it to decide if there will be more rows. --- dbdimp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dbdimp.c b/dbdimp.c index 7d4d88bb..29bf4274 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -4215,7 +4215,7 @@ bool mariadb_st_more_results(SV* sth, imp_sth_t* imp_sth) sv_2mortal(newSVuv(mysql_num_fields(imp_sth->result))) ); - if (imp_sth->row_num) + if (imp_sth->row_num || use_mysql_use_result) DBIc_ACTIVE_on(imp_sth); } @@ -4691,7 +4691,7 @@ IV mariadb_st_execute_iv(SV* sth, imp_sth_t* imp_sth) /** Store the result in the current statement handle */ num_fields = mysql_num_fields(imp_sth->result); DBIc_NUM_FIELDS(imp_sth) = (num_fields <= INT_MAX) ? num_fields : INT_MAX; - if (imp_sth->row_num) + if (imp_sth->row_num || imp_sth->use_mysql_use_result) DBIc_ACTIVE_on(imp_sth); if (!use_server_side_prepare) imp_sth->done_desc = FALSE; @@ -5255,7 +5255,9 @@ mariadb_st_fetch(SV *sth, imp_sth_t* imp_sth) return Nullav; } - if (imp_sth->currow >= imp_sth->row_num && !mysql_more_results(imp_dbh->pmysql)) + if (imp_sth->use_mysql_use_result) + imp_sth->row_num++; + else if (imp_sth->currow >= imp_sth->row_num && !mysql_more_results(imp_dbh->pmysql)) DBIc_ACTIVE_off(imp_sth); num_fields= mysql_num_fields(imp_sth->result); @@ -6571,7 +6573,7 @@ my_ulonglong mariadb_db_async_result(SV* h, MYSQL_RES** resp) } else { num_fields = mysql_num_fields(imp_sth->result); DBIc_NUM_FIELDS(imp_sth) = (num_fields <= INT_MAX) ? num_fields : INT_MAX; - if (imp_sth->row_num) + if (imp_sth->row_num || imp_sth->use_mysql_use_result) DBIc_ACTIVE_on(imp_sth); } imp_sth->warning_count = mysql_warning_count(imp_dbh->pmysql); From 6d67dbe2d7c46c60c7813e8dd873e2128dd133a1 Mon Sep 17 00:00:00 2001 From: Robert Vollmer Date: Mon, 28 Nov 2022 12:11:29 +0100 Subject: [PATCH 3/4] Fix combination of mariadb_use_result and mariadb_server_prepare It isn't supported and an error is thrown when mariadb_server_prepare_disable_fallback is set. With the fallback enabled though there's an infinite loop because mariadb_st_fetch() doesn't know that the fallback was used and goes into the wrong branch. --- dbdimp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dbdimp.c b/dbdimp.c index 29bf4274..197f787b 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -4696,6 +4696,9 @@ IV mariadb_st_execute_iv(SV* sth, imp_sth_t* imp_sth) if (!use_server_side_prepare) imp_sth->done_desc = FALSE; } + + /* Remember whether we actually used server side prepare */ + imp_sth->use_server_side_prepare = use_server_side_prepare; } imp_sth->warning_count = mysql_warning_count(imp_dbh->pmysql); From 92e12acb5a23b9a111948a9939ab8ec2d58dadd6 Mon Sep 17 00:00:00 2001 From: Robert Vollmer Date: Mon, 28 Nov 2022 12:17:51 +0100 Subject: [PATCH 4/4] Fix $sth->finish() for mariadb_use_result mysql_use_result() requires fetching all rows before executing the next query, otherwise we'd get an error 2014 (Commands out of sync). This can be relevant if the script leaves the result loop early. If it explicitly calls $sth->finish() that would croak, if it undefines $sth it would get a warning. If it doesn't do anything and executes another query, it croaks. With this fix, the pending rows are fetched silently. For multi-result sets we could use mysql_store_result() for the remaining results, that would consume more memory to buffer all rows, rather than just fetching and discarding each individual row. --- dbdimp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dbdimp.c b/dbdimp.c index 197f787b..4c39e82f 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -4007,7 +4007,9 @@ static bool mariadb_st_free_result_sets(SV *sth, imp_sth_t *imp_sth, bool free_l if (next_result_rc == 0) { - if (!(imp_sth->result = mysql_store_result(imp_dbh->pmysql))) + imp_sth->result = imp_sth->use_mysql_use_result ? + mysql_use_result(imp_dbh->pmysql) : mysql_store_result(imp_dbh->pmysql); + if (!imp_sth->result) { /* Check for possible error */ if (mysql_errno(imp_dbh->pmysql)) @@ -4023,6 +4025,13 @@ static bool mariadb_st_free_result_sets(SV *sth, imp_sth_t *imp_sth, bool free_l imp_dbh->insertid = imp_sth->insertid = mysql_insert_id(imp_dbh->pmysql); } } + if (imp_sth->use_mysql_use_result) { + while (mysql_fetch_row(imp_sth->result)) {} + if (mysql_errno(imp_dbh->pmysql)) + mariadb_dr_do_error(sth, mysql_errno(imp_dbh->pmysql), + mysql_error(imp_dbh->pmysql), + mysql_sqlstate(imp_dbh->pmysql)); + } if (imp_sth->result && (mysql_more_results(imp_dbh->pmysql) || free_last)) { mysql_free_result(imp_sth->result);