Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

DBI error and $@

by notsoevil (Pilgrim)
on Dec 06, 2001 at 20:18 UTC ( [id://129953]=perlquestion: print w/replies, xml ) Need Help??

notsoevil has asked for the wisdom of the Perl Monks concerning the following question:

Following an example in "Programming the Perl DBI" concerning error handling for transactions (which recently seen implemented Randal Schwartz's "Perl of Wisdom" column in this month's "Linux Magazine"), I tried doing something similiar with a test (which of course will be expanded into actual application later):
my $dbh = DBI->connect("dbi:Pg:dbname=test_db", $user, $pass, { RaiseE +rror => 1, AutoCommit => 0 }); eval { $dbh->do('UPDATE a SET x = y'); $dbh->commit(); }; if ($@) { warn "flurg!: $@"; }
The problem is the output in my logs is: 'flurg!: '

$@ is not being printed. However, if I print $DBI::errstr instead in the warning, I get the expected error (eg: table a doesn't exist).

I am sure this is all is my fault and I've just misused the examples.

--
notsoevil
--
Jeremiah 49:32 - And their camels shall be a booty. . .

Replies are listed 'Best First'.
Re: DBI error and $@
by Arguile (Hermit) on Dec 06, 2001 at 21:32 UTC
    Personally when I'm doing transaction handling I use Error or other exception handling modules. The addition of a little syntatic sugar make a lot of difference. You can also define your own error classes for more complex failovers.
    use Error qw(:try); # ... code passes ... try { # Execute a few queries $sth->execute( $str ); # If we're here everything is fine, let's commit. $dbh->commit; } catch Error with { my $err = shift; print "Transaction Failed: $err"; $dbh->rollback; };
Re: DBI error and $@
by frankus (Priest) on Dec 06, 2001 at 20:41 UTC

    try $dbh->errstr() instead of $@?

    --

    Brother Frankus.

    ¤

      No, perhaps I wasn't clear -- sorry. I said I can print the value of $DBI::errstr, but it was my understanding that "If there is a syntax error or runtime error, or a die statement is executed, an undefined value is returned by eval, and $@ is set to the error message."

      And from the examples I mention above, I thought that is what they are trying to catch for. They're not looking at $DBI::errstr, they're looking at $@. I want to know why and such.

      --
      notsoevil
      --
      Jeremiah 49:32 - And their camels shall be a booty. . .

Re: DBI error and $@
by broquaint (Abbot) on Dec 06, 2001 at 21:16 UTC
    I'm not entirely sure why the eval() is breaking, but $@ is not the variable you are looking for. That's because $@ contains what goes wrong inside an eval(), whereas DBI->errstr() will tell you what went wrong with the database.
    HTH

    broquaint

    Update: I believe that $@ is dependent on the DBI driver you're using, so it's probably best not to rely on it as a means of communicating what went wrong.

      This related to Transactions (or this is my intent). According to the 'Perl DBI' book (section 6.3.5 Combining Automatic Error Handling with Transactions):
      Imagine combining the automatic error detection of the DBI's RaiseError attribute and the error trapping of Perl's eval { ... } and the error handling properties of transactions. The result is a simple yet powerful way to write robust applications in Perl.
      ...
      Using RaiseError helps here because it generates a message (or Perl $@ variable value) that includes the underlying error from the driver, and the driver and method names.
      If $@ is not containing the error message, why does the example from the book (and Randal's article) use this method of trapping errors?

      --
      notsoevil
      --
      Jeremiah 49:32 - And their camels shall be a booty. . .

        I believe you have misunderstood the advice: you combine the approaches, you don't replace one with the other.

        You have to set $@ yourself by calling die in the normal way:

        eval { $db->do($sql) or die $db->errstr(); $db->commit(); } if ($@) { warn "DB error: $@\n"; }

        In addition to what the anonymous monk has to say (I'll admit it, it was me, not logged in), take a look at the code that creates the DB handle in that example, where RaiseError is set to 1 (i.e. true). That means the die is automatically called on a DB error, so it's functionally equivalent to the code "AM" provided.

        HTH

        I mistrust all systematizers and avoid them. The will to a system shows a lack of integrity -- F. Nietzsche

Re: DBI error and $@
by runrig (Abbot) on Dec 06, 2001 at 23:00 UTC
    This doesn't make sense, you say $@ is not being printed, but it must be set to something or else you wouldn't even be executing that warn statement. Are you getting a warning from somewhere else in the script (and are all of your warnings as descriptive as this one? :)

    Update: When I'm in doubt about variables that must be there, but don't appear to be, then I resort to something like:

    my $hex = unpack("H*", $@); warn "Warning: [$@] [$hex]";
    You've got the latest versions of DBI & DBD??
      There is no other code. :)

      There are no other warnings. :)

      I know it should print something. However it is not, hence my confusion.

      I'd really just like an explanation of the examples in the Perl DBI book and/or Randal's article on why they used the format:

      eval { $dbh->do($statement); $dbh->commit(); } if ($@) { $dbh->rollback(); die $@; }
      I believe my sample code is an example of this (save the $dbh->rollback, but that isn't the issue). The examples check $@ and then die with it, after a rollback. If $@ isn't being printed (interpolated into my warn string), how does the conditional execute? If it is executing (and hence doing a rollback) when $@ does not have a printable value, this may affect my transactions.

      Or am I just completely batty?

      --
      notsoevil
      --
      Jeremiah 49:32 - And their camels shall be a booty. . .

        Hmmm ... using mysql v3.23.36, Perl 5.6.0, and DBI v1.20:
        # connect with RaiseError set to true eval { $dbh->do('UPDATE a SET x = y'); $dbh->commit(); }; if ($@) { warn "flurg!: $@"; warn "flurg!: ", $dbh->errstr(); }
        yielded:
        DBD::mysql::db do failed: Table 'mysql.a' doesn't exist at ./test_db_e +val.pl line 20. flurg!: DBD::mysql::db do failed: Table 'mysql.a' doesn't exist at ./t +est_db_eval.pl line 20. flurg!: Table 'mysql.a' doesn't exist at ./test_db_eval.pl line 25.

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        F--F--F--F--F--F--F--F--
        (the triplet paradiddle)
        
Re: DBI error and $@
by notsoevil (Pilgrim) on Dec 06, 2001 at 23:46 UTC
    Either I am a complete idiot (highly possible) or there is something quirky going on (less possible).

    I run the code again, and I get the print out of $@ as expected. In the same log, only a few lines above, I can see where it wasn't printing out.

    I could have swore that I didn't make any changes since I was getting the error, but perhaps I just did.

    I am going to keep an eye on the code and its output and keep running tests with it. Thanks to everyone for trying to help.

    --
    a complete idiot
    --
    Jeremiah 49:32 - And their camels shall be a booty. . .

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://129953]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (4)
As of 2024-04-19 05:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found