Hi,
there is a strange problem with usage of DBI inside the FETCH method
of a tied hash. I have inherited the maintenance of a perl module
which contains some configuration data and was filled in the past
by hand but currently all data are maintained by a database
and the data are to many to generate the module now for backward
compatibility. So I have changed the module that its new method
returns now a ref to a tied hash and the data is fetching on
request from the database using DBIx::Recordset (was not my
choice). Because the module exists only for backward compatibility
I can't change any code, where it is used. Some values of
this hash are again hash ref's and in this case the problem
occurs. Here the stripped code to simple reproduce the bug:
#################################################################
package Tie::HashTest;
require Tie::Hash;
require DBI;
@ISA = qw(Tie::StdHash);
sub FETCH ($$)
{
my $self = shift;
my $key = shift;
DBI->connect('dbi:NullP:','','')
if $key eq 'dbi';
return {true => 1};
}
package main;
my %h;
tie %h, 'Tie::HashTest';
print STDERR 'DBI-VERSION: ', $DBI::VERSION, "\n\n";
for my $key (qw(other dbi))
{
my $val = $h{$key};
print STDERR $key, "\t", $val->{true};
print STDERR ':', $h{$key}->{true}, "\n";
}
#################################################################
If the returned hash ref will be first assigned to a scalar
then all works but if the returned hash ref will be directly
dereferenced it crashes:
DBI-VERSION: 1.21
other 1:1
dbi 1Can't use an undefined value as a HASH reference at dbi_tst.pl line 32.
I have also tried the current DBI version:
DBI-VERSION: 1.35
other 1:1
dbi 1Can't use an undefined value as a HASH reference at dbi_tst.pl line 32.
but it is the same. I use Perl 5.6.1 without thread support build on
HP-UX 10.20 using the HP ANSI-C compiler. But I have tried it with
other Perl build (5.5.3 on HP-UX, 5.6.1 build with GCC on HP-UX and
Solaris) and other DBD-drivers it is always the same.
I have also tried to use a existing DBIx::Recordset as DataSource (in this
case DBI::connect will not called again in DBIx::Recordset::Setup...), but
it does not help because some other DBI methods are called. The only
solution is at the moment, to create the DBIx::Recordset object during
TIEHASH call, save it in the returned ref. and overload in the FETCH method
the new method of the used DBIx::Recordset subclass by
local *<DBIx::Recordset subclass>::new = sub {return <saved obj>};
because the API of the methods I use for data fetching don't have the
possibility to hand over the DBIx::Recordset object. This is very
tricky and unsatisfyingly (I don't like which kind of code).
regards, Silvio