DBIのちょっとしたTIPSです。DBIには connect する時に
DBI->connect('dbi:mysql:database=hoge', 'root', 'whatever', { ... });
とオプションを渡すことができます。(たとえば RaiseError) 。このオプションのひとつに HandleError というものがあってデバッグにはなかなか便利なので紹介してみます。端的にいうと HandleError でサブルーチンを登録しておくと、エラーが発生したときにこのサブルーチンを使ってエラーを投げてくれるようになります。以下は具体例。
# MyDB.pm
package MyDB;
use strict;
use warnings;
use Carp ();
use DBI;
sub new {
bless {}, shift;
}
sub connect {
my ($self) = @_;
$self->{dbh} = DBI->connect(
'dbi:mysql:database=dbix_thin_test', 'root', 'root',
{ RaiseError => 1, HandleError => &Carp::confess } # here
);
}
sub select {
my ($self, $sql) = @_;
my $sth = $self->{dbh}->prepare($sql); # error!
$sth->execute();
}
1;
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin qw($Bin);
use lib "$Bin";
use MyDB;
my $db = MyDB->new;
$db->connect();
$db->select("select * from not_exist");
と書いてわざと MyDB#select でエラーになるようにしておき、このスクリプトを実行します。
すると
$ perl ~/script/perl/dbi_handle_error.pl
DBD::mysql::st execute failed: Table 'dbix_thin_test.not_exist' doesn't existDBI::st=HASH(0x248a900) at /home/kazuhiro/script/perl/MyDB.pm line 23
MyDB::select('MyDB=HASH(0x21b8df0)') called at /home/kazuhiro/script/perl/dbi_handle_error.pl line 11
のように DBI->connectの HandleError で渡した Carp::confess が呼ばれ、エラーになった時にスタックトレースが表示されます。HandleError を指定しない場合は
$ perl ~/script/perl/dbi_handle_error.pl
DBD::mysql::st execute failed: Table 'dbix_thin_test.not_exist' doesn't exist at /home/kazuhiro/script/perl/MyDB.pm line 23.
DBD::mysql::st execute failed: Table 'dbix_thin_test.not_exist' doesn't exist at /home/kazuhiro/script/perl/MyDB.pm line 23.
のようになってしまい、実際にエラーが発生している箇所と問題のクエリの関連性がわかりにくいですが、HandleErrorで Carp::confess を指定しておくとファイル名と行番号がわかるのでどこでエラーになっているかあたりがつけやすいと思います。(この例だとメソッドのネストが少ないのでそのありがたみがわからないですが...)
以上、生DBIでもこんなマニアックなオプションがあるんだよという紹介でした。ZIGOROuさんの生 DBI ユーザーのための DBI Cookbook (1)を見ててよく思うのですが、DBIってなかなか奥が深いです。