Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number

DBI error and $@

by notsoevil (Pilgrim)
on Dec 06, 2001 at 20:18 UTC ( #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.

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.

      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.


    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?

      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.


        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?

      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(); }
        DBD::mysql::db do failed: Table 'mysql.a' doesn't exist at ./test_db_e line 20. flurg!: DBD::mysql::db do failed: Table 'mysql.a' doesn't exist at ./t line 20. flurg!: Table 'mysql.a' doesn't exist at ./ line 25.


        (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?

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

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (3)
As of 2023-12-08 16:54 GMT
Find Nodes?
    Voting Booth?
    What's your preferred 'use VERSION' for new CPAN modules in 2023?

    Results (36 votes). Check out past polls.