Subject: | No error messages or error codes on Windows and RaiseError doesn't work |
This bug was originally reported by Ralf Neubauer at
http://bugs.mysql.com/bug.php?id=62846
Description:
Since DBD::mysql 4.019, if $sth->do() or $sth->execute() fails, the
error code $sth->err and the error string $sth->errstr are undef on
Windows. Also -- I suppose DBI uses one of these methods to implement
this functionality -- the RaiseError attribute doesn't work. No error is
raised. If you followed the latter advice from the DBI documentation 'It
is always important to check the return status of "execute" (and most
other DBI methods) for errors if
you're not using "RaiseError".' you get silent data corruption, if
something failed and RaiseError doesn't work.
This can be a security issue, because you don't notice an attacker
trying out SQL injections; the program just runs without noticing the error.
I already sent a description (with further links to other bug tracker
entries -- there are too many bug trackers involved) to the list
(http://lists.mysql.com/perl/4415), but nothing happened. In short,
since 4.019 there is conditionally compiled code depending on
MYSQL_ASYNC. On Windows MYSQL_ASYNC is 0, but the code responsible for
transferring the error codes is -- by error -- only compiled #if
MYSQL_ASYNC. Thus everything is ok under linux, but it doesn't work
under windows.
Note the build system is broken under Windows, too: even after trying
for several days and making some progress, I still can't build DBD-mysql
myself and thus I rely on the ActiveState packages.
How to repeat:
C:\>perl -le "use strict; use warnings; use DBI; my $h =
DBI->connect('dbi:mysql:xxx', 'yyy','zzz', {RaiseError => 0, PrintError
=> 0}) or die $DBI::errstr; my $s = $h->prepare(q/select * from
does_not_exist/) or die $DBI::errstr; $s->execute or die 'DBI:' .
$DBI::errstr . ' sth:', $s->errstr;"
Use of uninitialized value $DBI::errstr in concatenation (.) or string
at -e line 1.
Use of uninitialized value in die at -e line 1. DBI: sth: at -e line 1.
Note exactly the same happens with RaiseError=1, i.e. RaiseError doesn't
work:
C:\>perl -le "use strict; use warnings; use DBI; my $h =
DBI->connect('dbi:mysql:xxx', 'yyy','zzz', {RaiseError => 1, PrintError
=> 1}) or die $DBI::errstr; my $s = $h->prepare(q/select * from
does_not_exist/) or die $DBI::errstr; $s->execute or die 'DBI:' .
$DBI::errstr . ' sth:', $s->errstr;"
Use of uninitialized value $DBI::errstr in concatenation (.) or string
at -e line 1.
Use of uninitialized value in die at -e line 1. DBI: sth: at -e line 1.
Suggested fix:
--- dbdimp.c.orig 2011-08-20 20:35:59.000000000 +0200
+++ dbdimp.c 2011-10-19 16:40:08.484738100 +0200
@@ -3252,6 +3252,7 @@
}
#if MYSQL_ASYNC
}
+#endif
Safefree(salloc);
if(rows == -2) {
@@ -3259,9 +3260,7 @@
mysql_sqlstate(svsock));
if (DBIc_TRACE_LEVEL(imp_xxh) >= 2)
PerlIO_printf(DBILOGFP, "IGNORING ERROR errno %d\n", errno);
- rows = -2;
}
-#endif
return(rows);
}