Pardon the top-posting, but I'd rather get the answer up front instead
of buried deep in the chain.

Turns out I was wrong - I got my test scripts crossed. Removing the ()
did not fix the problem.

However, it did make me think a little and once I got into the
debugger, I figured out what really happened. The subclassed module
does not do subclassing properly - it takes the result of a
DBI->connect and just reblesses it. I guess its a minor miracle that
anything works at all.

I got the disconnect to work by doing a

bless($dbh,"DBI::db");

just before the disconnect.

So, we are going to add a disconnect method to the subclass class that
does just that. It's ugly and kludgy, but going back and rewriting
MDISS::DB properly would require cycles that we just don't have.

On 5/23/05, Matthew Persico <[EMAIL PROTECTED]> wrote:
> On 5/23/05, Matthew Persico <[EMAIL PROTECTED]> wrote:
> > On 5/23/05, Hemanth Kumar <[EMAIL PROTECTED]> wrote:
> > > What happens when you replace $dbh->disconnect(); with $dbh->disconnect;
> > >
> > > hth
> > > Hemanth
> > >
> >
> > Son-of-a-monkey's-uncle, that worked!
> >
> > Okay, now I'm lost. Does anyone want to explain this behavior? The
> > best that I can come up with is that:
> > 1) there is some deep magic in DBI
> > 2) the () changes the signature of the disconnect call in such a way
> > that it does not match the prototype given in DBI and that since
> > MDISS::DB is a subclass of DBI and not a DBI, we've confused perl in a
> > bizzare way.
> 
> 3) The () force a lookup for a function. Without the parens, the
> lookup is free to find the function reference which points to the
> implementation in the appropriate DBD?
> 
> > >
> > > -----Original Message-----
> > > From: Matthew Persico [mailto:[EMAIL PROTECTED]
> > > Sent: Monday, May 23, 2005 10:27 AM
> > > To: dbi-users@perl.org
> > > Subject: Re: DBI->disconnect is not a DBI method. Read the DBI manual.
> > > at ff.pl line 224
> > >
> > > On 5/20/05, Tim Bunce <[EMAIL PROTECTED]> wrote:
> > > > On Fri, May 20, 2005 at 10:08:36AM -0400, Matthew Persico wrote:
> > > > > Has anyone ever seen this message? I have a valid handle - all of my
> > >
> > > > > database commands work. The command is simply
> > > > >
> > > > > $dbh->disconnect();
> > > >
> > > > I'd guess that $dbh contains the string "DBI".
> > > >
> > > > Tim.
> > > >
> > >
> > > That was a rather sparse message I posted Friday. A few more details are
> > > in order. If anyone has any ideas after reading this, thanks in advance.
> > >
> > > Perl 5.6.1
> > > DBI 1.37
> > > DBD::Sybase 1.00
> > >
> > > Yes, I am stuck with these versions (esp. Perl) for the foreseable
> > > future.
> > >
> > > The connection is created in a module I have inherited (consultant long
> > > gone...) called MDISS::DB that contains, among other things, this
> > > code:
> > >
> > > BEGIN { # setup as a subclass of DBI
> > >         @MDISS2::DB::EXPORT = (@DBI::EXPORT);
> > >         @MDISS2::DB::EXPORT_OK = (@DBI::EXPORT_OK);
> > >         @MDISS2::DB::EXPORT_TAGS = (@DBI::EXPORT_TAGS);
> > >         @MDISS2::DB::ISA = qw(DBI DBI::db Exporter);
> > >         @MDISS2::DB::db::ISA = qw(DBI::db MDISS2::DB Exporter);
> > >         @MDISS2::DB::st::ISA = qw(DBI::st MDISS2::DB Exporter);
> > >         DBI::init_rootclass('MDISS2::DB');
> > > }
> > >
> > > and this code:
> > >
> > > sub new {
> > >
> > >         my %args = ();
> > >         my $proto = undef;
> > >
> > >         if (scalar(@_)) {
> > >                 ($proto, %args) = @_;
> > >         }
> > >
> > >         my %clone = ();
> > >         my $class = undef;
> > >         my $self = undef;
> > >         my $private = undef;
> > >         my %login = ();
> > >         my $n = undef;
> > >
> > >         $n = 'MDISS2::DB->new()';
> > >
> > > =item   legacy code
> > >
> > >     my($proto, %args, %clone, $class, $self, $private, %login, $n) = @_;
> > >
> > > =cut
> > >
> > >         %clone = ();
> > >         if(ref($proto)) {
> > >                 if($proto->can('_private')) {
> > >                         $private = $proto->_private();
> > >                         if(exists($private->{'login'})) {
> > >                                 %clone = %{$private->{'login'}};
> > >                                 if(exists($clone{'driver'}) &&
> > > exists($args{'driver'})) {
> > >                                         croak("$n - cannot clone
> > > '$args{'driver'}' from '$clone{'driver'}'")
> > >
> > > unless(uc($args{'driver'}) eq uc($clone{'driver'}));
> > >                                 }
> > >                         }
> > >                 }
> > >         } #endif
> > >
> > >
> > >         $args{'driver'} = ucfirst(lc($args{'driver'})) || 'Sybase';
> > >         if($args{'driver'} eq 'Oracle') {
> > >                 %login = mdiss_oracle_login(%clone, %args);
> > >         } else {
> > >                 %login = mdiss_sybase_login(%args);
> > >         }
> > > # print Dumper(%login);
> > >
> > >         ### This connectDBI is a wrapper that mashals args and makes the
> > >         ### typical DBI->connect call.
> > >         $self = connectDBI(%login) || croak("$n - failed to login to
> > > database: $DBI::errstr, aborting");
> > >         # $class = ref($proto) || $proto;
> > >         $class = 'MDISS2::DB';
> > >         bless($self, $class);
> > >
> > >         $private = $self->_private();
> > >         $private->{'login'} = {%login};
> > >         $private->{'cachedQueries'} = [];
> > >         $private->{'cachedStatements'} = {};
> > >         $private->{'cachedColumns'} = {};
> > >         $private->{'cachedColumnTypes'} = {};
> > >         $private->{'portiaDb'} = $ENV{'AM_PORTIA_DB_APO'};
> > >         if($DEBUG > 1) {
> > >                 my $pri = $self->_private();
> > >                 print STDERR "$n - DBH Private Data:\n";, Dumper($pri);
> > >         }
> > >
> > >         $ALL_DBH{"$self"} = $self;
> > >         return $self;
> > > } # end new()
> > >
> > > All of the database calls we are making using handles (such as do)
> > > created by MDISS::DB (do) and calls made by sths created from these
> > > handles all work.
> > >
> > > The only one that doesn't work is the disconnect. When I debug, I get to
> > > line 654
> > >
> > > sub disconnect {        # a regular beginners bug
> > >     Carp::croak("DBI->disconnect is not a DBI method. Read the DBI
> > > manual."); }
> > >
> > > Now, I've read the DBI manual and I seem to have missed the discussion
> > > of the regular beginners bug.
> > >
> > > Here is some DBI_TRACE=1 ouput. The first section is the conenction and
> > > the first prepare statement
> > >
> > >     ->
> > > DBI->connect(dbi:Sybase:server=A2S1_402;appname=MDISS2::DB;hostname=nydu
> > > x-ast402,
> > > AMGDEV, ****)
> > >     -> DBI->install_driver(Sybase) for solaris perl=5.006001 pid=27583
> > > ruid=8030 euid=8030
> > >        install_driver: DBD::Sybase version 1.00 loaded from
> > > /opt/perl/lib/site_perl/5.6.1/sun4-solaris/DBD/Sybase.pm
> > >     <- install_driver= DBI::dr=HASH(0x52c8e8)
> > >     <-
> > > connect('server=A2S1_402;appname=MDISS2::DB;hostname=nydux-ast402'
> > > 'AMGDEV' ...)= DBI::db=HASH(0x1243d0) at DBI.pm line 582
> > >     <- STORE('PrintError' 1)= 1 at DBI.pm line 622
> > >     <- STORE('AutoCommit' 1)= 1 at DBI.pm line 622
> > >     <- STORE('Username' 'AMGDEV')= 1 at DBI.pm line 625
> > >     <- connect= DBI::db=HASH(0x1243d0)
> > >     <- STORE('dbi_connect_closure' CODE(0xa0472c))= 1 at DBI.pm line 639
> > >     <- err= undef at DBI.pm line 936
> > >     <- STORE('RaiseError' 1)= 1 at DBI.pm line 950
> > >     <- STORE('PrintError' 0)= 1 at DBI.pm line 951
> > >     <- STORE('AutoCommit' 0)= 1 at DBI.pm line 952
> > >     <- STORE('syb_show_sql' 1)= 1 at DBI.pm line 954
> > >     <- STORE('syb_show_eed' 1)= 1 at DBI.pm line 955
> > > 1   <- prepare('use mdissdb' undef)= DBI::st=HASH(0xa09364) at
> > > Sybase.pm line 150
> > >     <- execute= -1 at Sybase.pm line 151
> > >     <- err= undef at Sybase.pm line 152
> > >     <- rows= -1 at Sybase.pm line 153
> > >     <- FETCH('syb_more_results')= undef at Sybase.pm line 154
> > >     <- do('use mdissdb')= -1 at DBI.pm line 971
> > >     <- DESTROY= undef at DBI.pm line 973
> > >     <- err= undef at DBI.pm line 973
> > >     <- STORE('private_AMG_DBI_data' HASH(0xa120c4))= 1 at DBI.pm line
> > > 988
> > > 1   <- FETCH('private_mdiss')= undef at DBI.pm line 1168
> > >     <- EXISTS('private_mdiss')= '' at DB.pm line 196
> > >     <- STORE('private_mdiss' HASH(0x10f220))= 1 at DB.pm line 196
> > >     <- FETCH('private_mdiss')= HASH(0x10f220)0keys ('private_mdiss'
> > > from cache) at DB.pm line 199
> > > 1   <- FETCH('private_mdiss')= HASH(0x10f220)6keys ('private_mdiss'
> > > from cache) at DBI.pm line 1168
> > >     <- EXISTS('private_mdiss')= 1 at DB.pm line 196
> > >     <- FETCH('private_mdiss')= HASH(0x10f220)6keys ('private_mdiss'
> > > from cache) at DB.pm line 196
> > >     <- FETCH('private_mdiss')= HASH(0x10f220)6keys ('private_mdiss'
> > > from cache) at DB.pm line 199
> > >     <- prepare('
> > >                                 select am_md_rule_id
> > >                                 from am_md_rule
> > >                                 where name = ?
> > >                         ' undef)= DBI::st=HASH(0xa12088) at DB.pm line
> > > 282
> > >
> > > I'l skip the rest of the trace - propriatary stuff that just works. At
> > > the end:
> > >
> > > code:
> > >
> > >     print "dbh Active is $dbh->{Active}
> > > Kids is $dbh->{Kids}
> > > ActiveKids is $dbh->{ActiveKids}
> > > just before disconnect
> > > ";
> > >     $dbh->disconnect();
> > >
> > > trace:
> > > dbh Active is 1
> > > Kids is 1
> > > ActiveKids is 0
> > > just before disconnect
> > > DBI->disconnect is not a DBI method. Read the DBI manual. at ff.pl line
> > > DBI->223
> > >     <- DESTROY= undef
> > >     <- DESTROY= undef
> > >     <- DESTROY= undef
> > >
> > >
> > >
> > >
> > > --
> > > Matthew O. Persico
> > >
> >
> >
> > --
> > Matthew O. Persico
> >
> 
> 
> --
> Matthew O. Persico
> 


-- 
Matthew O. Persico

Reply via email to