Hi !
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.xstSat 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);