tags:

views:

134

answers:

3

I have a database query that I am running inside an eval, to trap the error. Problem is that the error message is outputting to console, even though it is being trapped. How do I stop the error message from doing this, as I want to parse it myself and spit back my own messages?

my $dbh = DBI->connect('dbi:Pg:dbname=database;host=localhost',
    'user', 'pass', 
    {RaiseError => 1}
);

eval{
    $sth = $dbh->prepare($sql);
    $sth->execute;
};

if($@){
    #Do my parse/print stuff here I know
}
+1  A: 

eval { } will trap a fatal error (from a die or Carp::croak call), but not a non-fatal error message (from warn or carp). To handle warning messages, see how to install a warning handler in documentation for %SIG or warn.

A trivial workaround is to use a trivial warning handler inside your eval block.

eval {
    local $SIG{__WARN__} = sub { };
    ...
};

See also: perlfaq7: How do I temporarily block warnings?

mobrule
Blah blah blah are you sure it's a good idea to suppress your warning messages blah blah.
mobrule
**@mobrule:** I think that is what was being asked. `local $SIG{__WARN__} = sub {}` is the obvious choice. http://perldoc.perl.org/functions/warn.html
vol7ron
While this is a correct solution to suppressing warnings in an `eval` block, specifying `PrintError => 0` in the `connect` method is the right way to handle the OP's situation.
Sinan Ünür
They both do. It depends on what the OP wants - both answers are valid, but doesn't DBI use `$SIG{__WARN__}` and `Carp` internally?
vol7ron
Instead of setting a WARN handler globally, you can use a HandleError attribute to the particular statement handle. You don't want to change what everything else is doing just because one object is causing a problem.
brian d foy
**@brian d foy:** which is why I suggested `HandleError` as a comment in *runrig's* selected answer. -- btw, you're not setting it globally, you're setting it locally to the `eval` block. If these are the only two statements being called then this is a perfect solution. Sometimes I like using alternative solutions just as a reminder that the functionality is there, in case it could be used elsewhere, where it's more purposeful.
vol7ron
+6  A: 

You can specify 'PrintError => 0' in your connect call (or use HandleError):

my $dbh = DBI->connect('dbi:Pg:dbname=database;host=localhost', $user, $passwd, {
  PrintError => 0,
  RaiseError => 1,
});

Or to set per statement handle:

my $sth = $dbh->prepare("SELECT * from my_table");
$sth->{PrintError} = 0;
$sth->execute();
...etc.

Also, don't depend on $@ for indicating an error. A better way to use eval is:

my $result = eval {
  ...
  $sth->...etc.
  1;
}
unless ($result) {
  # Do error handling..log/print $@
}
runrig
Perhaps `HandleError` could also be used, if you're going down the (Print|Raise)Error route.
vol7ron
@vol7ron HandleError is also a possibility, but I've never found a good use for it since I usually just wrap blocks of code in eval { } to catch all exceptions, not just DBI errors.
runrig
You can set some of these attributes per statement handle too.
brian d foy
+8  A: 

It's not a good idea to trap and ignore errors, whether they are fatal or not. Also, it is not advisable to check $@ in the way you are doing it (see the questions on this site about perl exceptions for better ways to trap exceptions; I use Try::Tiny below, which is arguably the lightest-weight route of all).

Instead of proceeding with a DBI operation when an earlier one might have failed, you should check error conditions at every step:

use strict; use warnings;
use Try::Tiny;

try {
    my $sth = $dbh->prepare($sql) or die $dbh->errstr;
    $sth->execute or die $sth->errstr;
} catch {
    print "got error $_\n";
    # return from function, or do something else to handle error
};

And remember, always use strict; use warnings; in every module and script. Your code excerpt suggests that you are not yet doing this.

Ether
@Ether My code example was the _minimum_viable_ example of what I was working with. Therefore, things like warnings and strict have been stripped out, as well as other eval statements. But thanks for playing. Your answer is saved from completely bagging on the question and a downvote by the useful link provided for Try:Tiny.
Ben Dauphinee
@Ben: I inferred this from `$sth = ...` rather than `my $sth = ...`. There's no need to be rude.
Ether
@Ether The same to yourself. It's quite rude to assume anything about how a script is built from 7 lines of code.
Ben Dauphinee
@Ben We can only see what you post.
Sinan Ünür