On Mon, Nov 24, 2003 at 02:34:13PM -0700, Wiggins d Anconia wrote:
>
> # localize the setting of dbh handle attributes
> {
> local $dbh->{AutoCommit} = 0;
> local $dbh->{RaiseError} = 1;
>
> # now perform our steps inside of an eval, allowing us to catch the
> # exceptions triggering a rollback
>
> my $sth;
> eval {
> my $st = "SELECT * ....";
> my @bind = ( bind values );
>
> $sth = $dbh->prepare($st);
> $sth->execute(@bind);
>
> $dbh->commit;
> }
> if ($@) {
> $dbh->rollback;
> # throw my normal exception stuffs here
> }
> }
>
> Questions:
> 1) Can/should I do the 'local' setting of the attributes within the eval
> block without causing any other issues? I can't think of reasons not
> to, but maybe you can?
The current version of the DBI (and probably some previous ones) has a
bug whereby the automatic STORE that restores the previous attribute value
when the block scope ends, will clear $DBI::err and $DBI::errstr (and
$h->err, $h->errstr) so they won't hold the error details anymore.
When using RaiseError that's not a big problem as the error message is in $@
> 2) If the answer to number 1 is no, then presumably 'rollback' throws an
> exception itself so I would have to catch it too with an 'eval'? Can
> rollback fail?
Yes, e.g., network connection failure / server down etc.
> If I can move the settings inside of the 'eval' then
> rollback failing should do "normal" error reporting correct, is that
> returning undef or true?
Yes.
> 3) Similar to #2, setting AutoCommit to 0 before setting the RaiseError
> would mean I need to check that it succeeds (which is just checking the
> boolean context of the attribute) moving it into the eval should mean I
> can put it after the RaiseError and let the eval catch its exception as
> well, correct?
Setting AutoCommit to 0 is defined by the DBI spec to be a fatal
error (regardless of RaiseError) if the driver/database can't handle
transactions at all.
[The mysql situation is a little blurred here but I'd expect setting
AutoCommit to 0 to not be an error for DBD::mysql, but (hopefully)
commit() could warn if there's no in-transaction-state to commit.
But I digress...]
Tim.