Perl: catch error without die
Solution 1
Okay, found the solution, apparently I needed __WARN__
instead of __DIE__
and this piece of code needed to be in the top of the file, before where the error was thrown, unlike the example I read stated :)
Solution 2
DBI connect(...) failed: ORA-12154: TNS:could not resolve the connect identifier specified (DBD ERROR: OCIServerAttach) at ...
How would I go about catching this ?
To catch and handle this level of error, use eval in block form, "eval { ... }". This will catch any die that happens in the sub code. If the code within an eval block dies, it will set $@ and the block will return false. If the code does not die, $@ will be set to ''.
Using signal handling via SIG{WARN} and SIG{DIE} is troublesome since they are global, there are also race conditions to consider (what happens if I get a signal while I'm handling a different signal? etc. The traditional issues of signal based computing). You're probably writing single-threaded code, so you're not worried about concurrency issues of multiple things calling die, but there is the user to consider (maybe he'll send a SIGKILL while you're trying to open the DBI connection)
In this specific case, you are using DBI. With DBI, you can control what happens in the case of error, if it should die, warn, or fail silently and wait for you to check the return status.
Here is a basic example of using eval { ... }.
my $dbh = eval { DBI->connect( @args) };
if ( $@ )
{
#DBI->connect threw an error via die
if ($@ =~ m/ORA-12154/i )
{
#handle this error, so I can clean up and continue
}
elsif ( $@ =~ m/SOME \s* other \s* ERROR \s+ string/ix )
{
#I can't handle this error, but I can translate it
die "our internal error code #7";
}
else
{
die $@; #re-throw the die
}
}
There are some minor issues with using eval this way, having to do with the global scope of $@. The Try::Tiny cpan page has a great explanation. Try::Tiny handles a minimal Try/catch block setup and handles localizing $@ and handling the other edge cases.
Solution 3
Include this in your SIG{__DIE__}
block:
### Check if exceptions being caught.
return if $^S;
This will prevent your handler from being used on exception-based code that generates a die within an eval block.
Related videos on Youtube
Pmarcoen
Updated on April 19, 2022Comments
-
Pmarcoen about 2 years
I'm playing around with error handling and got a little problem. I connect with a database using the DBI module.
I do my own error handling by using a subroutine that I call upon an error.
I can catch my own dies and handle them just fine but when my database connection fails, the DBI module apparently prints out it's own die :
DBI connect(...) failed: ORA-12154: TNS:could not resolve the connect identifier specified (DBD ERROR: OCIServerAttach) at ...
How would I go about catching this ?
I tried using
$SIG{__DIE__}
like so :local $SIG{__DIE__} = sub { my $e = shift; print "Error: " .$e; };
This is on the bottom of my main file, in this file I also call the connect subroutine that is available in a module of my own. I also tried putting this piece of code on the bottom of my module but it still prints the error without the
Error:
in front of it.
-
Ether about 14 yearsThat's correct, this was a warning and not a death, and the handler must be installed first. You can install it in any module if you wrap it in a
BEGIN{}
. -
Pmarcoen about 14 yearsThis was the way I had it at first, eval however does not catch warnings which I wanted to report as well. Therefor I must use SIG{WARN}.