DBIで文字コード変換
<追記:2007/7/19>
この記事のスクリプトはうまく動きません。その後の顛末をこちらに書きました↓
http://d.hatena.ne.jp/omoon/20070719/1184819170
追記>
人力検索に質問してしまうほど苦戦。詳細は下記を参照のこと。
http://q.hatena.ne.jp/1183789393
要は、スクリプトの文字コードがutf8で、mysqlの文字コードがsjis。しかも、mysqlのバージョンが4.0.24なので、
set names xxxx;
も使えない。
また別のサービスが稼働中のため、文字コードを変えることもできない、と。
じゃあ、perlのスクリプト側で変換するにはどんな方法がいいのかなあ、ということ。
人力検索でいただいた回答には、DBD::mysqlの方をいじるのでは、という話もあって、下記の本を手に入れたりして、色々調べてみたのだが、今ひとつぴんとこなかった。なんかおおごと過ぎるような気が。。。
- 作者: 川合孝典
- 出版社/メーカー: アスキー
- 発売日: 2002/03
- メディア: 単行本
- 購入: 2人 クリック: 18回
- この商品を含むブログ (12件) を見る
今回やりたいことはいたってシンプルで、
(1) mysqlに投げるsql文をsjisに変換する
(2) 返ってきた結果をutf8に変換する
の2点。
もちろん毎回、
$sth = $dbh->prepare("select * from foo where bar = ?"); $sth->execute(encode('sjis', $baz));
てしたり、
while ($data = $sth->fechrow_arrayref()) { @$data = map { encode('utf8', $_) } @$data; }
みたいに変換すればうまくいくことはわかっているんだけど、結構規模の大きなアプリになりそうなので、いちいちそんなこともしてられない。
ということで、perlもカタコト、サブクラスとかいってもあんまりピンと来ない僕が、DBIのサブクラスを作って、ちょちょいとやってみよう、というのが、今回のお題です。
現在(2007/7/10)のところ、最終的な解決にはいたっていません。進展あり次第追記していくつもりです。
CPAN読んでがんばってみた
http://search.cpan.org/~timb/DBI-1.58/DBI.pm#Subclassing_the_DBI
ここにあるじゃない!!
ステートメントハンドラは、DBI::dbに返させる、excuteとかfetchとかはDBI::stにあるとかいうことだと思うのだけれど、何しろperl自体がカタコトなので、理解するのにすごく時間がかかった。
Data::Dumperなどで、ちまちまダンプしながら、どんな値が返ってきているのか確認しながら、何とか書いたのがこれ。
思いっきり中途半端でして、fetchrow_hashrefで取ってくることしか考えていない。とりあえず、動作はしたよーというレベルですが、晒します。
色々教えてください。
人力検索の回答でコメントいただいても結構です。
package MyDBI; use strict; use warnings; use base qw(DBI); package MyDBI::db; use base qw(DBI::db); sub prepare { my ($dbh, @args) = @_; my $sth = $dbh->SUPER::prepare(@args); return $sth; } package MyDBI::st; use base qw(DBI::st); sub execute { my ($sth, @args) = @_; foreach (@args) { $_ = Encode::encode('cp932', $_); } return $sth->SUPER::execute(@args); } sub fetchrow_hashref { my ($sth, @args) = @_; my $ref = $sth->SUPER::fetchrow_hashref(@args); foreach (%$ref) { $_ = Encode::decode('cp932', $_); } return $ref; } 1;
で、これを、
use MyDBI; my $dbh = MyDBI->connect('DBI:mysql:databese:localhost', 'user', 'pass'); my $sth = $dbh->prepare("select * from foo where bar=?"); $sth->execute("テスト"); foreach ($sth->fetchrow_hashref) { print $_->{bar}; # テストと出力される }
みたいな感じで使う。
いまのところここまで。今日はここからがんばります。