Following the DBI docs a coworker of mine tried to modify the return value
($_[2]) in a HandleError sub to implement automatic retry on error.
This works as documented with DBI::ExampleP and DBD::mysqlPP but not with DBD::mysql (and presumably all Driver.xst based DBDs).
DBD::mysql uses DBIs Driver.xst Template to build itself and therefore uses (among others) XST_mUNDEF to return an error condition. This return value has the READONLY flag set and is aliased into the HandleError-subs @_ by XS_DBI_dispatch.
Apparently the $_[2] access in the handler silently creates a local copy to work on, while I would expect something like "attempt to modify read-only value". (Why not ?)
My XS-knowledge is _very_ limited but I tried the following patch (to the execute method only) and it fixes our testcase:
--- DBI-1.37/Driver.xst Tue May 13 16:00:10 2003
+++ DBI-1.37-test/Driver.xst Sat Jun 14 12:49:44 2003
@@ -456,7 +456,7 @@
if (retval == 0) /* ok with no rows affected */
XST_mPV(0, "0E0"); /* (true but zero) */
else if (retval < -1) /* -1 == unknown number of rows */
- XST_mUNDEF(0); /* <= -2 means error */
+ ST(0) = sv_newmortal(); /* <= -2 means error */
else
XST_mIV(0, retval); /* typically 1, rowcount or -1 */
IMHO this is a slight problem with the HandleError interface, I would suggest that XS_DBI_dispatch makes sure that READONLY SVs on the return stack are replaced by a writable copy before passing them to the handler, otherwise this will happen again.
Can someone with more experience please comment on this ?
Thank you very much, regards,
Bjoern
Testcase follows:
Environment: DBI 1.37, DBD::mysql 1.1027, perl 5.8.0 DEVEL 17013, Mac OS X 10.2.6, also on 5.6.1 Linux x86
-- 8< --
use DBI; use strict; use warnings; use Data::Dumper; use Devel::Peek;
sub handler {
warn Dumper( [EMAIL PROTECTED] );
$_[1]->set_err(0,"");
warn "before\n"; Dump( $_[2] );
$_[2] = 42;
warn "after\n"; Dump( $_[2] );
return 1;
}my $dbh = DBI->connect("DBI:mysql:host=localhost", undef, undef,
{ HandleError => \&handler } );
my $sth = $dbh->prepare("GNARZ");#DBI->trace(9); my $r = $sth->execute; Dump($r);
