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

Reply via email to