-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mariadb_use_result
is broken
#173
Comments
Interesting. I tried your example and it not only prints Active: no, but also fetchrow_array does return anything and moreover at the end of program perl prints additional error:
As issue is related to the use_result feature, I looked into the mysql_use_result() and mysql_num_rows() documentation where is written: https://dev.mysql.com/doc/c-api/5.7/en/mysql-use-result.html
https://dev.mysql.com/doc/c-api/5.7/en/mysql-num-rows.html
Which is interesting because DBD::MariaDB is calling I think that the main issue here is total absence of use_result tests. Except very simple t/rt91715.t there is no test. Could you try following patch if it fixes issue for you? diff --git a/dbdimp.c b/dbdimp.c
index 0f44089221f2..5853c6776dc8 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -4355,7 +4355,11 @@ static my_ulonglong mariadb_st_internal_execute(
if (mysql_errno(*svsock))
rows = -1;
else if (*result)
+ {
rows = mysql_num_rows(*result);
+ if (use_mysql_use_result && rows == 0)
+ rows = -2;
+ }
else {
rows = mysql_affected_rows(*svsock);
} |
Thanks for the quick reply! Your fix works, however I find I have trouble understanding why it works and |
During the weekend I have looked at this issue and I implemented fix and added missing tests. I pushed code into my mariadb_use_result branch: master...pali:DBD-MariaDB:mariadb_use_result Looks like that you figured out also other issues which I have in my branch :-) I was planning to open a pull request with my fixes after CI testing patch is merged. |
Indeed, quite some similarities. I hope I can find some time tomorrow to review your commits, maybe you also want to see if you can borrow a few things from my commits. I see we solved most things the same way, however from my "outsider" perspective the explicit checks for use_mysql_use_result are easier to understand than the return code -2. The docs for mysql_use_result() also mention that mysql_num_rows() will give a valid result after all rows have been fetched. |
This does not fix the issue that Look at the test which I added. And you cannot check
Yes, but this is basically unusable. You do not know number of rows, so you cannot know if you fetched all rows. What you can do is to move the next row and if it fails (you get NULL) then you know that you fetched all of them and you can call |
Well, the DBI docs also says:
Which is exactly what I have implemented. I can imagine that the following would be useful for some scripts, e.g. when writing the results to a CSV: my $sth = $dbh->prepare('SELECT id FROM sometable', {mariadb_use_result => 1});
$sth->execute();
while (my $id = $sth->fetchrow_array()) {
print $id, "\n";
}
printf "Wrote %d rows\n", $sth->rows(); If you prefer -1 while fetching is in progress, how about setting the correct row count when it's safe to do so - after fetching all rows? diff --git a/dbdimp.c b/dbdimp.c
index 91c9ad4..827f6f7 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -5263,6 +5263,8 @@ process:
mariadb_dr_do_error(sth, mysql_errno(imp_dbh->pmysql),
mysql_error(imp_dbh->pmysql),
mysql_sqlstate(imp_dbh->pmysql));
+ if (imp_sth->row_num == (my_ulonglong)-2)
+ imp_sth->row_num = mysql_num_rows(imp_sth->result);
if (!mysql_more_results(imp_dbh->pmysql))
DBIc_ACTIVE_off(imp_sth);
return Nullav;
Oh, I wasn't suggesting to call |
Looks like you're covering all the combinations, great!
Oh ok, and that is (should be) allowed while the statement is still active? I checked the source code and indeed it seems that would be possible to switch it on/off while fetching results, affecting the next result received. Which would only make sense if the application wants to handle results of multi-statement queries differently, but maybe there's an edge-case for that. Fine. By the way, I hope you don't find my comments disrespectful - I'm new to this codebase and some circumstances aren't obvious, so I might be pressing for something that has good reasons not to be done. ;) |
I have no objections for this feature.
It is not only for (rather) rare multi-statement queries. It is possible to call my $sth = $dbh->prepare("SELECT id FROM t WHERE name = ? AND req = ?");
$sth->execute("name1", "req1");
...
$sth->execute("name1", "req2");
... This idiom is documented and also marked as typical call sequence in DBI documentation: https://metacpan.org/pod/DBI#Outline-Usage
Of course not :-) |
Good. It's just those two lines, so I assume you'll put that into a commit yourself? Or shall I open a PR to your branch?
Sure, I do that a lot. Yeah, you're right, it's possible that someone changes the attribute while they're still fetching rows for the first |
See also https://dev.mysql.com/doc/c-api/5.7/en/c-api-threaded-clients.html
This applies not only for threads but also for multi-process application if it shares file descriptor with connection to server. I think that we do not have any tests for threads. And moreover there are two kinds of thread usage in perl. First is classic standalone perl application with threads and second is application written in any other language (e.g. C) which spawns two threads and initialize two separate perl interpreters (one in every thread). Well written Perl XS module should work correctly with both scenarios. Second scenario is used for example by Apache and mod_perl. I tried to handle possible issues in DBD::MariaDB but because there is no automated test, there could be bugs (and such test is hard to write as it needs to be via man perlembed). So mysql_use_result() just makes everything harder in multi thread or multi process scenarios. |
I'd definitely avoid using database/statement handles anywhere else than in the process that created it 😉 But as discussed in the other PR, DESTROY can get in your way without your knowledge. Even if you just connected to the database before forking, the exiting child process will close the connection. And if there were pending results for a multi-statement query, they will be finished (and therefore taken away from the parent process), also when you use mysql_store_result(). So yes, there are some more things to consider with mysql_use_result(), but also other approaches have their traps. |
Or let's just say: The application developer should carefully consider whether they want to use mariadb_use_result, but if they do, the library should handle it correctly, provided they follow the rules you mentioned. |
Sorry that it took longer time, but now both AppVeyor CI (Windows) and Github Actions CI (Linux) are implemented and enabled for all new pull requests. So I opened a pull request #181 for mariadb_use_result attribute from my branch. Please look at it. You can implement other features mentioned in this discussion on top of it. |
Upstream changes: 1.23 2023-09-10 - Add a missing break (perl5-dbi/DBD-MariaDB#163) - Signal error if mariadb_db_async_result() fails (perl5-dbi/DBD-MariaDB#162) - Update links to project website, issues and years - Fix compilation with some MariaDB client library 10.2 and 10.3 versions - Fix mariadb_use_result attribute (perl5-dbi/DBD-MariaDB#173) - Fix statements with multiple result sets in asynchronous mode - Fix mariadb_sockfd attribute for Windows - Croaks when changing AutoCommit attribute fails (perl5-dbi/dbi#104) - Various documentation and tests fixes - Fix support for MariaDB Connector/C prior to 3.1.3 version - Fix usage of Win32::GetShortPathName() in Makefile.PL - Build release tarball in TAR format (instead of PAX) - Allow to query and change mariadb_multi_statements attribute - Add connect option mariadb_auth_plugin for specifying auth plugin - Fix support for MySQL 8.0+ client library (perl5-dbi/DBD-MariaDB#191) (perl5-dbi/DBD-mysql#329) - Add Github Actions CI and Cirrus CI (FreeBSD) for automated testing 1.22 2022-04-22 - Disable usage of libmysqld.a from MySQL 8.x series - Install README.pod into DBD/MariaDB/ subdirectory (perl5-dbi/DBD-MariaDB#146) - Do not export driver private C functions - Fix typo in error message - Fix compatibility with new MariaDB client and server versions (perl5-dbi/DBD-MariaDB#164) (perl5-dbi/DBD-MariaDB#167) (perl5-dbi/DBD-mysql#333)
The following example displays
Active: no
and has no results:It works fine without
mariadb_use_result
. It works fine withDBD::mysql
, both with and withoutmysql_use_result
.It might be related to 4f47a06. The
execute()
call returns0E0
rows, but withmariadb_use_results
this doesn't mean that there are no results.Trace:
The text was updated successfully, but these errors were encountered: