http://www.perlmonks.org?node_id=686832

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

Hi All,
  I recently updated my Database routines to be object orientated, but I seem to have broken carp..
Example:-
package db_base; use strict; use DBI; use CGI::Carp qw( fatalsToBrowser ); sub new { my ( $class, $DSN, $user, $pass, $param ) = @_; $param = {} unless ref( $param ); my $self = { param => { %$param, dsn => $DSN, user => $user, pass => $pass, }, }; bless( $self, $class ); return $self; }#new sub connect_db { my $self = shift; unless ($self->{param}->{connect}) { $self->{dbh} = DBI->connect( $self->{param}->{dsn}, $self->{pa +ram}->{user}, $self->{param}->{pass} ) || croak("Cannot connect to database: $DBI::errstr\n$::bac +khtml"); $self->{param}->{connect} = 1; }#unless }#sub sub insert { my ( $self, $table, $columns, $data ) = @_; $self->{param}->{success} = 0; my $sql = "INSERT INTO `$table` (`" . join( "`,`", @$columns ) . ' +`) values(' . join( ",", map {'?'} @$columns ) . ')'; my $sth = $self->{dbh}->prepare($sql); $sth->execute(@$data) && {$self->{param}->{success} = 1} || croak( +"Cannot insert to $table: SQL = $sql\n $DBI::errstr\n$::backhtml"); }#sub

If for instance there is a problem connecting, with code like:-
use db_base; my $dbobj = new db_base( 'dsn', 'user', 'pass'); $dbobj->connect; $dbobj->insert( 'test_table', [ 'column' ], [ 'value' ]);
I get an error like:-
Cannot insert to test_test_table: SQL = INSERT INTO `test_test_table` +(`column`) values(?) Table 'affiliate.test_test_table' doesn't exist at c:/inetpub/wwwroot/cgi-bin/affiliate/db_base.pm line 52

Shouldn't this be showing my calling script and not the module?
What am I missing :s


Lyle

Update: Crackers2 pointed out my example didn't properly illustrate the problem I'm having, it was an example showing correct behavious of another scripts carp. The new example above shows my problem

Replies are listed 'Best First'.
Re: Carp not working after change to objects
by Crackers2 (Parson) on May 16, 2008 at 01:52 UTC

    Your error says "Can't connect to data source" but the croak in your module says "Cannot connect to database."

    Maybe the DBI->connect call is croaking instead of coming back with a false value? Which would explain why it's showing your module in the error message, since it's the one calling DBI->connect

      Good point, my example didn't show the kind of error problem I'm having. I've updated my example to correctly illustrate it.

      Lyle
Re: Carp not working after change to objects
by snoopy (Curate) on May 16, 2008 at 04:06 UTC
    You've ommitted to set RaiseError => 1 in your DBI connect attributes.

    Therefore this has been raised as a warning not an error. That's why it's not being caught by CGI::Carp's error handler.

    Update: The following code illustrates, this.

    #!/usr/bin/perl use warnings; use strict; use CGI::Carp qw/fatalsToBrowser/; use DBI; # Without RaiseError #line 100 my $dbh1 = DBI->connect("dbi:SQLite:my.db","","",); $dbh1->do("select * from crud"); # bad query on $dbh1 # With RaiseError #line 200 my $dbh2 = DBI->connect("dbi:SQLite:my.db","","",{RaiseError => 1}); $dbh2->do("select * from crud"); # bad query on $dbh2
    The CGI::Carp handler error handler doesn't get invoked until the bad query on $dbh2.
      Thanks for the reply, but I'm pretty sure that's not it. I want DBI to just give me a warning, it's my own code that does a Croak. (I don't want to croak in all situations of a DBI's carp).
        Sorry this didn't help.

        Btw, I'm not able exactly replicate your error with my Sqlite driver. My prepare statement on an unknown table returns undef, not a valid statement handle.

        my $sth = $dbh1->prepare("insert into guff values (1,2,3)") or croak "prepare error" # dies here for me

        If you're not raising errors, be aware that prepare may return undef.

        Also consider localisd error handling. You still has the option of dieing or continuing:

        my $dbh = DBI->connect(... ,{RaiseError => 1}); do { local $SIG{__ERROR__} = \&my_handler; # database code }