DBIx::Handler と mysql_enable_utf8 と utf8mb42013年06月10日 21時52分

Perl で MySQL サーバーに接続するとき、DBIx::Handler を使っています。

my $handler = DBIx::Handler->new(
    $dsn, $username, $password,
    {
        RaiseError        => 1,
        RootClass         => 'My::DBI',
        mysql_enable_utf8 => 1,
    },
);

しかし、これだと "𠮷" (U+20BB7、いわゆる「つちよし」) など BMP 外の文字を保存しようとしたとき、テーブルの文字コードが utf8mb4 であっても "????" (疑問符 4 文字) に化けてしまいます。

ググったところ、mysql_enable_utf8 => 1 を指定した時点で DBD::mysql が接続時の文字コードを utf8 にしてしまうのが問題だそうです。(cf. おそらくはそれさえも平凡な日々: DBD::mysqlでmysql_enable_utf8しつつutf8mb4使いたいとき)

接続時に文字コードを utf8mb4 に指定しなおせばいいとのことですが、DBIx::Handler ではどうするのだろうとソースコードを眺めていたところ、new メソッドの第 5 引数の存在を知りました。

my $handler = DBIx::Handler->new(
    $dsn, $username, $password,
    {
        RaiseError        => 1,
        RootClass         => 'My::DBI',
        mysql_enable_utf8 => 1,
    },
    {
        on_connect_do     => ['SET NAMES utf8mb4'],
    },
);

これで BMP 外の文字も文字化けせず保存・取得できるようになったのですが、この第 5 引数は (DBIx::Handler 0.07 時点では) 文書化されていないので、使っていいものか心配です。

Callbacks を使っても期待通り動作するようなので、そちらのほうがよかったりするのでしょうか。

my $handler = DBIx::Handler->new(
    $dsn, $username, $password,
    {
        RaiseError        => 1,
        RootClass         => 'My::DBI',
        mysql_enable_utf8 => 1,
        Callbacks         => {
            connected => sub {
                $_[0]->do('SET NAMES utf8mb4');
                return;
            },
        },
    },
);

(SET NAMES をつかってはいけないという話もありますが、追いきれていません。)