[Update: I've been informed that you should be using DBIx::Class instead of Class::DBI because the latter is no longer supported, but I haven't had time to switch yet.]
The
DBI manpage describes
how to subclass DBI to override certain methods on database and statement handles (search for MySubDBI in the DBI manpage). If you are using
Class::DBI, however, the instructions there won't work and it won't be obvious why.
The secret to being able to override DBI methods when using Class::DBI (and subclasses like
Class::DBI::mysql) is to instead subclass
DBIx::ContextualFetch. That class is used by
Ima::DBI (a parent of Class::DBI) to add functionality to the database handles and statement handles even if you or Class::DBI thought your code was directly calling DBI->connect().
Here's a sample following the naming conventions in the DBI manpage. Note that the "connected" sub is not needed and is only provided as a sample which can be used to make sure that the subclassing is actually working for you.
package MySubDBI;
use strict;
use base 'DBIx::ContextualFetch';
package MySubDBI::db;
use base 'DBIx::ContextualFetch::db';
# Override methods for the database handle here. (Sample provided)
sub connected {
my $dbh = shift;
my ($dsn, $user, $pass, $attr) = @_;
warn "Connected to $dsn as $user";
return $dbh->SUPER::connected($dsn, $user, $pass, $attr);
}
package MySubDBI::st;
use base 'DBIx::ContextualFetch::st';
# Override methods for the statement handle here.
Important: When opening the database handle for your Class::DBI objects, you need to specify the following attribute in the
DSN string: "RootClass=MySubDBI" (where MySubDBI is the name of your subclass above). For example the DSN might look like:
"DBI:mysql(RootClass=MySubDBI):host=localhost;database=dbname"
Specifying RootClass in the %attr hash does not seem to be sufficient, possibly due to the way that DBIx::ContenxtualFetch overrides the attributes and tries to insert its own RootClass, but I didn't spend a lot of time trying to figure out exactly why.