in reply to DESTROY and DBI

Mark,

I think I see the problem. You are not returning the modified $self. You are returning the connection of opendb's instance of $self.

sub opendb { my $self=shift; $self->{_dbh}=DBI->connect(...); # return $self->{_dbh}; # Should return $self here return $self; }

Update: RMGir's responce is absolutely correct. Before posting this I should have asked if the self was blessed.

Kristofer A. Hoch

Replies are listed 'Best First'.
Re: Re: DESTROY and DBI
by RMGir (Prior) on Aug 27, 2002 at 12:48 UTC
    No, krisahoch, he can return the database handle and modify %{$self} as a side effect...

    Mark, is $self properly blessed into the package? Otherwise, DESTROY would never be called...

    It could also be the global cleanup order problem mentioned in this thread.

    Have you tried using this class only from a subroutine? Take the part of the code at the top level that uses this class, and wrap it in a sub. Then put

    $|=1; # make sure we see printouts and warns in order print "Before sub\n"; subThatUsesClass(); print "After sub, I _better_ have seen DESTROY happen...\n";
    If it's the random global cleanups causing the problem, having your variable as a lexical in the sub should get it cleaned up properly...
    --
    Mike

    Edit: Put in correct link to tilly's excellent description of the global cleanup problem...

      Hi Mike,
      Yes, of course I bless my object.
      I even tried this, but I think it is the same as during the exit.
      my $o=new MyClass; my $dbh=$o->opendb; warn $o->{_dbh}; warn $dbh; # the same as the previous line undef $o; exit;
      I cannot put it as a lexical in the sub because I have just written an entire framework (+5000 lines), consisting of a tree of packages in OO, and setting the DBI object as an attribute has an advantage of using persistant DB connections.

      This is the actual opendb routine

      sub opendb { my $self=shift; local($@); if ( not $self->{_dbh} or not $self->{_dbh}->ping) { eval{ $self->{_dbh}=$self->{_dbi}->connect() ; } ; if ( $@ ) { $self->Log('!',$@) and die "db gives error" ; } } $self->{_dbh}->{LongReadLen}=100000; # to handle Long column types $self->{_dbh}->{LongTruncOk}=0; # generates an error when the dat +a is too long $self->{_dbh}->{AutoCommit}=0; # Lets run transactional return $self->{_dbh}; }
      And I call this opendb as much as I like, without going to the db everytime. (note $self->{_dbi} is a object from my superclass of DBI). And the link to tilly's one, that was the one I was referring to, but using flyweightwrapper is a bit overshooting, I think.
      ---------------------------
      Dr. Mark Ceulemans
      Senior Consultant
      IT Masters, Belgium
        (Edit: I don't believe _dbh goes away before $self does, I think DBI is unloaded before the global cleanup happens; that's why I'm suggesting this END{} fix...)

        Hmmm, you don't need the total encapsulation features of the FlyweightWrapper, either...

        I'm betting packages get unloaded correctly. What happens if you add a hash at the package level in your class called instances, and do this:

        # private hash of instances my %instances; #... sub new { # ... build up $self, bless it, do whatever $instances{$self}=1; # ... whatever else you need to do... } #... sub DESTROY { # don't double-destroy return unless $instances{$self}; #... do whatever $instances{$self}=0; } END { foreach my $instance(keys %instances) { $instance->DESTROY() if $instances{$instance}; } }
        Offhand, I can't remember whether calling DESTROY directly is ok or not, but if not, you could get the same effect with a helper sub that DESTROY calls.
        --
        Mike

        Edit: I forgot to check $instances{$self} at the top of DESTROY