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

Help ?!?!?

Using DBI I call a PL/SQL package and hand it some variables. This package does some validation of the data, when the package is not happy with the data an SQL error is raised.

What I want to do is instead of having DBI die, I want to see the error in a variable so I can process this and send back an error to the user.

The variables are handed in via a webpage and errors should be returned on that page (thus the dislike of a die)

I have seen some solutions to this, but these usualy use a eval{} to solve the problem. Due to the application framework that I'm forced to work in this will not work as a die is always caught before my code can get to it.

So what I wat is a way to find the errors returned without death.

The ways I have atempted to get these errors from the DBI are:
- my $error = $dbh->errstr;
- my $error = $@

The problem is that both are always undefined no matter how may errors the package returns. So my question is how do I find the errors without having the DBI calling die

This is my config:
- Perl v5.6.1 built for sun4-solaris
- DBI DBI version 1.34
- Oracle DBD complited with Oracle 8.1.7 client

Replies are listed 'Best First'.
Re: DBI - PL/SQL error catching
by gmax (Abbot) on Jun 23, 2003 at 15:15 UTC

    If eval id not a viable solution, then you have to check every DBI call, but only after you instruct the DBI not to do anything in case of errors.

    #!/usr/bin/perl -w use strict; use DBI; # # ---- untested # my ($dns, $user, $password) = ("dbi:wathever:db","me","secret"); my $dbh = DBI->connect($dns,$user,$password, {RaiseError=>0 , PrintError=>0}) # <-- be quiet! or die "can't connect ($DBI::errstr)\n"; my $sth= $dbh->prepare("SELECT WRONG FROM NON_EXISTING"); if ($sth) { # fetch your records while (my $rec = $sth->fetchrow_arrayref()) { print "@$rec\n"; } } else { print "something was wrong: ", $dbh->errstr, "\n"; # deal with the problem here }

    Notice that you can't use $dbh->errstr after a failed connection, because the result would be an undefined $dbh.

    Be also aware that, using this approach, you are entirely responsible for error checking. If you skip a step, the next one will try to execute/prepare/fetch on a undefined handler. You need to test very thoroughly.

    Good luck!

    Update

    HandleError (which has been proposed in other answers) is a generalized error trapping system. If you set it, the DBI will use it before calling RaiseError. It is not a replacement for error checking, since it will handle all the error from a static point, without any knowledge of the program flow.

    If you want to do something sensible with your errors, you have to catch them one by one, either by evalling their death or by checking their result.

    HandleError can be useful for error logging or to modify/erase error messages before passing them to RaiseError. (The DBI docs offer some examples of that.)

    Remember that technological tricks are not replacement for good programming design.

    _ _ _ _ (_|| | |(_|>< _|
Re: DBI - PL/SQL error catching
by Lachesis (Friar) on Jun 23, 2003 at 15:21 UTC
    You'll really need to give a bit more code but a few things to look at are:

    If you don't want DBI to die then make sure that the RaiseError attribute is off.

    Checking the errstr method is the right way to go for getting the error but you must check it as soon as you can since most DBI method calls will reset it to undef.

    You mention that you can't use eval blocks due to your app framework. have you considered using a local die handler to override the behaviour and then use an eval block?
    { local $SIG{__DIE__} = sub {# feedback code here}; eval { # your DBI code }; }
    Outside of the block your framework's handler will be in effect.

    DBI also provides a HandleError attribute which sets an error handler specifically for errors from DBI. Check the docs for more info on this DBI
Re: DBI - PL/SQL error catching
by crouchingpenguin (Priest) on Jun 23, 2003 at 15:01 UTC

    Have you tried looking in $DBI::errstr ?


    cp
    ----
    "Never be afraid to try something new. Remember, amateurs built the ark. Professionals built the Titanic."
Re: DBI - PL/SQL error catching
by erasei (Pilgrim) on Jun 23, 2003 at 16:53 UTC
    As Lachesis said, the HandleError attribute is probably what you are looking for. I use it in most of the cases where I need to report something back to the screen in a cgi. There are other methods, but this is one of the cleanest, and easiest to use.
    my $dbh = DBI->connect("DBI:mysql:test:localhost", "user", "pass", { RaiseError => 0, PrintError => 0 } ); $dbh->{HandleError} = sub { print "Error received: $DBI::errstr\n"; exit; }; my $sth = $dbh->prepare("SELECT wibble FROM flubble"); $sth->execute();
Re: DBI - PL/SQL error catching
by Tomte (Priest) on Jun 23, 2003 at 14:59 UTC

    Couldn't you override $SIG{__DIE__} in a very small block of code? like

    { $old_handler = $SIG{__DIE__}; $SIG{__DIE__} = sub { # test for dbi error and do things or "redie" +}; #DBI call $SIG{__DIE__} = $old_handler; }
    Or would this be horribly unperlish?

    Update: As always: I don't mind being stupid, and so a downmod is as welcome as a ++ to a good node; I'd just like to get explained why the node is --'ed, so I can learn ;-P

    Update II: you live and learn, Lachesis answer ++, disregard my code.

    regards,
    tomte


    Hlade's Law:

    If you have a difficult task, give it to a lazy person --
    they will find an easier way to do it.