DBIで文字コード変換その後
http://d.hatena.ne.jp/omoon/20070710/1184034594
http://q.hatena.ne.jp/1183789393
このあたりに書いていたことの顛末です。とりあえず、この形で様子を見る、というのができたので書いときます。とりあえず今のところ暫定版。変化があり次第追記します。
結論から言うと、DBIのサブクラスを作って実装しました。
主に、この部分を参考にしました。
http://search.cpan.org/~timb/DBI-1.58/DBI.pm#Subclassing_the_DBI
やったことは、以下の3つ。
上2つで、更新(insert, update, delete)は問題なし。参照もfetchrow_arrayref、fetchrow_hashrefで値がとれることは確認できました。
fetchrow_hashrefはfetch部分をオーバーライドすることでうまくいくのですが、fetchrow_arrayrefはfetchrow_arrayrefをオーバーライドしないとうまくいかないようです(それ以外は試していません。ま、追々)。
ということで、参照系はfetchとfetchrow_arrayrefをオーバーライド。
下記、実際のコードです。
1 package MyDBI; 2 use strict; 3 use warnings; 4 use base qw(DBI); 5 6 package MyDBI::db; 7 use base qw(DBI::db); 8 9 sub prepare { 10 my ($dbh, @args) = @_; 11 # sql文が入っている 12 @args = map { Encode::encode('cp932', $_) } @args; 13 return $dbh->SUPER::prepare(@args); 14 } 15 16 package MyDBI::st; 17 use base qw(DBI::st); 18 19 sub execute { 20 my ($sth, @args) = @_; 21 # プレースホルダの値が入っている 22 @args = map { Encode::encode('cp932', $_) } @args; 23 return $sth->SUPER::execute(@args); 24 } 25 26 sub fetch { 27 my ($sth, @args) = @_; 28 my $row = $sth->SUPER::fetch(@args) or return; 29 foreach my $val (@$row) { 30 $val = Encode::decode('cp932', $val); 31 } 32 return $row; 33 } 34 35 sub fetchrow_arrayref { 36 my ($sth, @args) = @_; 37 my $array_ref = $sth->SUPER::fetchrow_arrayref(@args) or return; 38 foreach my $value (@$array_ref) { 39 $value = Encode::decode('cp932', $value); 40 } 41 return $array_ref; 42 } 43 44 1;
http://d.hatena.ne.jp/omoon/20070710/1184034594
に書いていたコードでは正常に動かない。
色々突っ込みどころは満載ですが、特に28行目と37行目の
or return;
が要ります。でないと、ループします。というかしました。(apacheのエラーログ爆発した。)
さあ、これで、こんな感じでutf8のスクリプトから呼び出しても、、
use MyDBI; my $dbh = MyDBI->connect('DBI:mysql::localhost', 'user', 'pass'); my $sth; $sth = $dbh->prepare("update foo set bar=? where baz=?"); $sth->execute('あいうえお', 'あ'); $sth = $dbh->prepare("select bar, baz from foo where baz=?"); $sth->execute('あ'); while (my $str = $sth->fetchrow_arrayref) { my ($foo, $bar) = @$str; }