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

I've been rewriting a database module to make a connection during it's constructor (previously each method opened and closed the connection). I figured I could also centralise closing connections by adding a DESTROY method. However, even though I'm checking the db handle still exists in DESTROY, when I try disconnecting I get these warnings

DB disconnect failed: $DBI::err=, $DBI::errstr= during global destruction.
Can't read $DBI::err, last handle unknown or destroyed during global destruction.
Can't read $DBI::errstr, last handle unknown or destroyed during global destruction.

I could just change it back, it was working fine before, but I'm curious as to why this fails while the handle still seems to exist. Anyone know? The relevant bits (I hope) are below:

sub new() { my $class = shift; my $self = {}; $self->{'database'} = "dbi:Sybase:database=$config{'DB_NAME'};serv +er=$config{'DB_SERVER'};hostname=$config{'DB_HOST'};port=$config{'DB_ +PORT'}"; $self->{'username'} = $config{'DB_USERNAME'}; $self->{'password'} = $config{'DB_PASSWORD'}; bless ( $self , $class ); $self->{'dbh'} = $self->connect(); return $self; } sub DESTROY { my $self = shift; if ( $self->{'dbh'} ) { $self->close(); } } sub connect() { my $self = shift; my $dbh = DBI->connect( $self->{'database'}, $self->{'username'}, +$self->{'password'} ); if ( !defined( $dbh ) ) { ... } else { return $dbh; } } sub close() { my $self = shift; my $dbh = shift || $self->{'dbh'}; unless ( $dbh->disconnect() ) { warn "DB disconnect failed: \$DBI::err=$DBI::err, \$DBI::errst +r=$DBI::errstr"; } }

Replies are listed 'Best First'.
Re (tilly) 1: using DESTROY to DBI disconnect
by tilly (Archbishop) on Aug 22, 2001 at 07:46 UTC
    It is happening because you are running on a version of Perl prior to 5.8.

    Unfortunately Perl 5.8 doesn't yet exist, but when the current development branch becomes stable, it will be the first one which has reliable destruction mechanics for data which survives to global destruction.

    See the thread Re (tilly) 1: Tie & Destroy, OOP for a discussion of the issue and some possible solutions, and Class::FlyweightWrapper for a very slow implementation of the wrapper method I came up with to work around global destruction for some simple situations. (Yours qualifies as simple.)

Re: using DESTROY to DBI disconnect
by Cine (Friar) on Aug 21, 2001 at 22:36 UTC
    If you are running under mod_perl, none of this is actually necessary since Apache::DBI (can) automaticly connect at the start of a child and wont disconnect, for perfomance reasons.

    T I M T O W T D I
Re: using DESTROY to DBI disconnect
by chromatic (Archbishop) on Aug 22, 2001 at 07:15 UTC
    The DBI book (and presumably the fine DBI manual) suggest that the package vars are very short lived. They're associated with the last used handle, and, presumably, wear red shirts on away missions.

    What happens if you use $dbh->err() and $dbh->errstr() instead?

      The package variables ($DBI::err and $DBI::errstr) are very shortlived because they are changed everytime an access is made to the DBI (well nearly everytime).

      Thus if you have two statements then this

      $sth1->execute; $sth2->execute; print "Statement 1 failed" if $DBI::err;
      is wrong, as $DBI::err contains the error from $sth2.

      The DBI book (and the DBI pod) therefore recommends that you use $sth1->err and $sth2->err instead if possible. (They are marignally faster to access as well).