Subject: | Cached statements hold strong references to bind values |
Attached find a test demonstrating a contrived but real case of circular
reference leak. Clearing CachedKids makes the test pass, which made me
assume the problem is as noted in the subject.
Subject: | dbi_bindval_leak.t |
use warnings;
use strict;
use Test::More;
use DBI;
use Scalar::Util 'weaken';
{
package _Stringifying::Structure;
use overload '""' => sub { 42 };
}
my $weak_registry;
{
# the leak happens seemingly regardless of DBD used
my $dbh = DBI->connect('dbi:SQLite::memory:', undef, undef, { AutoCommit => 1 });
#my $dbh = DBI->connect(@ENV{map { "DBICTEST_MYSQL_$_" } qw(DSN USER PASS)}, { AutoCommit => 1 });
my $sth = $dbh->prepare_cached('SELECT ?');
# this is a simplified example - think of a deeply nested set of objects that
# *happen* to link to something that holds a ref to the current $dbh
my $bindval = bless {
reference_to_dbh => $dbh,
}, '_Stringifying::Structure';
weaken ($weak_registry->{bindval} = $bindval);
weaken ($weak_registry->{dbh} = $dbh);
weaken ($weak_registry->{sth} = $sth);
$sth->execute($bindval);
is_deeply ($sth->fetchall_arrayref, [[ 42 ]], 'result brought back');
# this would make tests pass
#%{$dbh->{CachedKids}} = ();
}
for (sort keys %$weak_registry) {
ok (!defined $weak_registry->{$_}, "No leaks of $_");
}
done_testing;