On Wed, Oct 27, 2004 at 12:38:13PM +0200, Kurt George Gjerde wrote:
> Hi,
>
> Hopefully someone can explain this to me.
>
> The attached script causes an object's destructor not to be called!
>
> This happens when a non-existing hash key is bound to a DBI statement
> handle with execute() (or bind_param()) (see the save() method).
I'd guess (I've no time to check) that the when the driver copies
the value supplied it also copies the "lvalue magic" that's used
to enable assignment into 'non existant' hash entries. Consider:
sub foo { $_[0] = 42 }
foo($hash{bar});
print "$hash{bar}\n";
and I'd guess that that lvalue magic holds a ref to the hash (object)
and that's what prevents DESTROY being called when you'd expect.
> If the hash key exists (in the object / blessed hashref) then it's ok
> (also for undefined values). If not, the destructor (DESTROY) is not
> called; not even during global garbage collection.
No idea off-hand why that should happen. Thanks for the test case.
You could make my life easier if you could integrate that test case
into the DBI test suite and send me a patch (diff). Once it's in
the test suite I'm sure to fix it before the next release.
Any chance you could you do that for me?
Meanwhile, you could change
$sth->execute($self->{name});
to
$sth->execute(my $temp = $self->{name});
or
$sth->execute(do { $self->{name} });
or
$sth->execute(eval { $self->{name} });
or suchlike, to avoid the problem.
Tim.
> My line-up is: Win32, Perl 5.8.3, DBI 1.43 (PPM states 1.45)
>
>
> -Kurt.
>
> --
> Kurt George Gjerde
> [EMAIL PROTECTED]
> ICQ:156792385 TLF:55588396
>
> Universitetet i Bergen
>
> #!/user/bin/perl
>
> #
> # The following script causes the object's destructor not to be called!
> #
> # This happens when a non-existing hash key is bound to a DBI statement
> # handle (in the save() method).
> #
> # If 'extra' is defined (in the object / blessed hashref) then it's ok.
> # If not, the destructor (DESTROY) is not called; not even during global
> # garbage collection.
> #
> # My line-up is: Win32, Perl 5.8.3, DBI 1.43 (PPM states 1.45)
> #
>
> #####
> # This script uses MySQL.
> #####
> # SEE BELOW FOR CREATE TABLE STATEMENT.
> #####
>
>
> use strict;
> use DBI;
>
> print "DBI VERSION: $DBI::VERSION\n\n";
>
>
> my $dbh = DBI->connect('DBI:mysql:database=test','root','PASSWORD');
>
> ### THIS IS OK
> # my $person = Person->new( name=>'Janet', age=>'38', extra=>'asd', dbh=>$dbh );
>
> ### THIS IS NOT
> my $person = Person->new( name=>'Janet', age=>'38', dbh=>$dbh );
>
>
> $person->save();
> $person->delete();
>
>
>
> ##########
>
> package Person;
>
> sub new {
> my ($class, %args) = @_;
> my $self = \%args;
> bless $self, $class;
> print "NEW $self->{name}\n";
> return $self;
> }
>
> sub DESTROY {
> my $self = shift;
> print "DESTROYED $self->{name}\n";
> }
>
> sub save {
> my $self = shift;
> my $sth = $self->{dbh}->prepare('insert into dbi_test (name, age, extra) values
> (?,?,?)');
>
> $sth->execute( $self->{name}, $self->{age}, $self->{extra} );
>
> $sth->finish;
> print "SAVED $self->{name}\n";
> }
>
> sub delete {
> my $self = shift;
> my $sth = $self->{dbh}->prepare('delete from dbi_test where name=?');
> $sth->execute($self->{name});
> $sth->finish;
> print "DELETED $self->{name}\n";
> }
>
>
> __END__
>
>
> # CREATE TABLE dbi_test (mysql)
>
> drop table if exists dbi_test;
>
> create table dbi_test (
> name varchar(32),
> age int,
> extra varchar(32),
>
> primary key (name)
> ) type=myisam;
>