Appologies to this list and especially Tim. The problem was in my subclass DBIx::Log4perl which suffered from an autovivification problem in the prepare method accurately described in the the DBI docs as:
"When calling a SUPER::method that returns a handle, be careful to check the return value before trying to do other things with it in your overridden method. This is especially important if you want to set a hash attribute on the handle, as Perl's autovivification will bite you by (in)conveniently creating an unblessed hashref, which your method will then return with usually baffling results later on." The main reasons I went down the wrong route was that the error I was getting was listed in the DBI Changelog but suggesting a different problem to the one I had and that DBD::DB2 and DBD::mysql worked whilst Oracle didn't. The reason for this is that Oracle errors on a prepare if a column does not exist and mysql/db2 don't so when you call selectrow_array with DBD::Oracle you get: subclass: selectrow_array calls selectrow_array subclass: prepare calls prepare which fails where upon my subclass failed to check the returned handle before using it. and with DB2 you get: subclass: selectrow_arrary calls selectrow_array DBI: selectrow_array _do_selectrow_array subclass: prepare calls prepare which succeeds and hence returned statement handle is good. Martin -- Martin J. Evans Easysoft Ltd, UK http://www.easysoft.com On 19-Jun-2006 Martin J. Evans wrote: > Hi, > > This is a fairly complex setup to explain so I'll initially try and keep > it simple and can expand it necessary. I'm getting the error > > $ perl a.pl > SV = RV(0x9fa6df4) at 0xa4450e8 > REFCNT = 1 > FLAGS = (TEMP,ROK) > RV = 0xa4451a8 > dbih_getcom handle HASH(0xa4451a8) is not a DBI handle (has no magic) at > /usr/lib/perl5/site_perl/5.8.8/DBIx/Log4perl/db.pm line 61. > > I'm using DBI 1.51 and DBD::Oracle 1.17 and DBIx::Log4perl 0.05. > DBIx::log4perl is overriding most methods in DBI. > > I'm running a script like this: > > use XXX::DB; > use Log::Log4perl qw(get_logger :levels); > Log::Log4perl->init_and_watch("/etc/log4.conf", 60); > my $zzz = XXX::DB->new( > {DSN =>"dbi:Oracle:XE",User=>"xxx", Pass=>"yyy"}); > my $dbh = $zzz->connect() or die "$DBD::errstr"; > $dbh->selectrow_array("select x_entry_status_id from v_market_entries > where entry_id = ? and market_id = ?", undef, 31, 11); > > where XXX:DB just provides some extra methods not in DBI to > avoid differences in DBD::oracle, DBD::DB2 and DBD::mysql and > uses Log::Log4perl::get_logger but it only comes in to this in that it > uses DBIx::Log4perl. > > If the script is changed to omit the DBIx::Log4perl it becomes: > > use DBI; > my $dbh = DBI->connect("dbi:Oracle:XE", "xxx", "yyy",{RaiseError => 1}) > or die "$DBD::errstr"; > $dbh->selectrow_array("select entry_status_id from v_market_entries > where x_entry_id = ? and market_id = ?", undef, 31, 11); > > The first thing to note is the second script works. > The second thing to note is that the column x_entry_id does NOT exist. > If the selectrow_array SQL is for a column that does exist it > works fine in both scripts. > > I've read: > > +One more thing to note: you must let the DBI do the handle creation. > +If you want to override the connect() method in your *::dr class then > +it must still call SUPER::connect to get a $dbh to work with. > +Similarly, an overridden prepare() method in *::db must still call > +SUPER::prepare to get a $sth. If you try to create your own handles > +using bless() then you'll find the DBI will reject them with an "is not > +a DBI handle (has no magic)" error. > > from the DBI changelog and it would suggest I've done something wrong > when overriding the methods in DBI. However, I believe I've done the > SUPER::connect and SUPER::selectrow_array correctly like this (this > example does omit some extra stuff on the private hash): > > sub connect { > my ($drh, $dsn, $user, $pass, $attr) = @_; > my %h = (); > my $dbh = $drh->SUPER::connect($dsn, $user, $pass, $attr); > return $dbh if (!$dbh); > # stuff setting $h{xxx} > $dbh->{private_DBIx_Log4perl} = \%h; > return $dbh; > } > sub selectrow_array { > my ($dbh, @args) = @_; > > my $h = $dbh->{private_DBIx_Log4perl}; > > if (wantarray) { > my @ret = $dbh->SUPER::selectrow_array(@args); > return @ret; > > } else { > my $ret = $dbh->SUPER::selectrow_array(@args); > return $ret; > } > } > > The comment in the DBI changelog suggests I've done something wrong. > Any ideas? If more info is required I can provide but I didn't want > to make this too convoluted initially. > > Thanks. > > Martin