On 08/09/10 21:24, Roode, Eric wrote:
> Hello all,
> 
>     I am trying to implement error handling in our stored procedures,
> but when I raise exceptions in the SQL code, they seem to disappear on
> their way back to the Perl app.  I've searched the archives, but
> haven't found an answer.
> 
>     I'm using DBI 1.609 with DBD::ODBC 1.23 under strawberry Perl 5.12
> on Windows 7, against a SQL Server 2000 database elsewhere on our LAN.
> 
> I've created a simple sproc to generate an error, as follows:
> 
>    create procedure error_test (@p1 varchar(50), @p2 int output)
>    as
>       set @p2=45;
>       raiserror ('An error was raised. Input was "%s".', 16, 1, @p1)
>       return 55
>    GO
> 
> Here is a simple Perl program to invoke it:
> 
>    use Modern::Perl;
>    use DBI;
>    
>    sub handle_error
>    {
>        my ($state, $msg, $native) = @_;
>        say qq{handle_error: \$state  is "$state".};
>        say qq{handle_error: \$msg    is "$msg".};
>        say qq{handle_error: \$native is "$native".};
>        return 1;
>    }
>    
>    my $dbh = DBI->connect('DBI:ODBC:driver={SQL
> Server};Server=xxxxx;Database=xxxxx,
>                           'xxxxx', 'xxxxx',
>                           {odbc_cursortype        => 2,
>                            odbc_default_bind_type => DBI::SQL_VARCHAR,
>                            odbc_err_handler       => \&handle_error,
>                            RaiseError             => 1,
>                            PrintError             => 0,
>                           });
>    
>    my $sth = $dbh->prepare('{? = call error_test(?, ?)}');
>    
>    # Set up parameters
>    my $retval;
>    my $p1 = 'Some input parameter';
>    my $p2 = 75;
>    $sth->bind_param_inout(1, \$retval, 4000, DBI::SQL_VARCHAR);
>    $sth->bind_param      (2,  $p1,           DBI::SQL_VARCHAR);
>    $sth->bind_param_inout(3, \$p2,       32, DBI::SQL_INTEGER);
> 
>    # Execute   
>    $sth->execute;
> 
>    # Show what we got
>    $_ = defined($_)? qq{"$_"} : '{NULL}' for ($retval, $p1, $p2);
>    say qq{After execute: \$retval is $retval.};
>    say qq{After execute: \$p1     is $p1.};
>    say qq{After execute: \$p2     is $p2.};
>    say 'Done.';
> 
> 
> Sadly, handle_error never gets called.  The output of the program is:
> 
>    After execute: $retval is {NULL}.
>    After execute: $p1     is "Some input parameter".
>    After execute: $p2     is "75".
>    Done.
> 
> On the other hand, if I do something like try to call a nonexistent
> stored procedure, handle_error does get invoked, and the output looks
> like:
>    handle_error: $state  is "42000".
>    handle_error: $msg    is "[Microsoft][ODBC SQL Server Driver][SQL
> Server]Could not find stored procedure 'blefh_error_test'.".
>    handle_error: $native is "2812".
> 
> 
> What do I have to do to detect the SQL exception?
> 
> Thanks,
> -- Eric
> 
> 

Works fine for me (although possibly under different conditions):

use DBI;
use strict;

sub handle_error
{
    my ($state, $msg, $native) = @_;
    print qq{handle_error: \$state  is "$state".}, "\n";
    print qq{handle_error: \$msg    is "$msg".}, "\n";
    print qq{handle_error: \$native is "$native".}, "\n";
    return 1;

}
my $dbh = DBI->connect('dbi:ODBC:baugi','sa','easysoft',
                      {odbc_err_handler => \&handle_error});

eval {
   local $dbh->{PrintError} = 0;
   $dbh->do("drop procedure t_raiserror");
};

$dbh->do(<<'EOT');
CREATE PROCEDURE  t_raiserror (@p1 varchar(50), @p2 int output)
AS
set @p2=45;
raiserror ('An error was raised. Input was "%s".', 16, 1, @p1)
return 55
EOT

sub test()
{
   my $sth = $dbh->prepare("{? = call t_raiserror(?,?)}");

   my ($p1, $p2) = ('fred', undef);
   $sth->bind_param_inout(1, \my $retval, 4000);
   $sth->bind_param(2, $p1);
   $sth->bind_param_inout(3, \$p2, 32);
   $sth->execute();

   print qq{After execute: \$retval is $retval.}, "\n";
   print qq{After execute: \$p1     is $p1.}, "\n";
   print qq{After execute: \$p2     is $p2.}, "\n";
}

#$dbh->{odbc_err_handler} = \&handle_error;

test();

$dbh->disconnect;

perl raiserror.pl
handle_error: $state  is "42000".
handle_error: $msg    is "[unixODBC][Easysoft][SQL Server Driver][SQL Server]An 
error was raised. Input was "fred".".
handle_error: $native is "50000".
DBD::ODBC::st execute failed: [unixODBC][Easysoft][SQL Server Driver][SQL 
Server]An error was raised. Input was "fred". (SQL-42000) at raiserror.pl line 
37.
After execute: $retval is .
After execute: $p1     is fred.
After execute: $p2     is .

I had to take out odbc_cursortype and odbc_default_bind_type as they produced 
other errors with the driver I was using.

You could send me a level 15 trace and I might see something but it looks like 
raiserror in your case is not raising an error.

I was using Perl 5.10.1, DBD::ODBC 1.24_3, DBI 1.609 on Ubuntu Linux with the 
Easysoft SQL Server ODBC Driver.

Martin
-- 
Martin J. Evans
Easysoft Limited
http://www.easysoft.com

Reply via email to