MySQLとPerlでUTF-8を扱う

とある環境で latin1 - latin1 の憎き動作をしていたので今後のために最小限のコードと設定をメモしておく

my.cnf

これ重要

[mysqld]
character_set_server = utf8

mysql クライアントで status と SHOW VARIABLES LIKE 'char%'; を発行し、 mysqld_safe で指定した my.cnf の内容が適用されているか、次のような結果を得られるかを確認する。

status
Server characterset:	utf8
Db     characterset:	utf8
Client characterset:	utf8
Conn.  characterset:	utf8
SHOW VARIABLES LIKE 'char%';
+--------------------------+------------------------------------------------------------+
| Variable_name            | Value                                                      |
+--------------------------+------------------------------------------------------------+
| character_set_client     | utf8                                                       |
| character_set_connection | utf8                                                       |
| character_set_database   | utf8                                                       |
| character_set_filesystem | binary                                                     |
| character_set_results    | utf8                                                       |
| character_set_server     | utf8                                                       |
| character_set_system     | utf8                                                       |
| character_sets_dir       | /usr/local/mysql-5.1.50-linux-i686-glibc23/share/charsets/ |
+--------------------------+------------------------------------------------------------+

テスト用のデータベース・テーブルを作る

データベース作成
CREATE DATABASE enctest;
テーブル作成
CREATE TABLE `utf8table` (
  `title_utf8` VARCHAR(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
テーブルの確認

DEFAULT CHARSET が utf8 になってるかを確認

SHOW CREATE TABLE utf8table;

アプリケーションのサンプル

テスト用なので最低限必要なオプションを DBI->connect() の \%attr にふたつ。

use strict;
use warnings;
use utf8;
use Encode;
use Data::Dumper;
use DBI;

my $dbh = DBI->connect('DBI:mysql:database=enctest;host=localhost', 'foo', 'bar',
    {
        mysql_enable_utf8 => 1,
        on_connect_do => ['SET NAMES utf8'],
    }
);

my $sth = $dbh->prepare(q{
    INSERT INTO utf8table (title_utf8)
         VALUES (?)
});
$sth->execute('いろは' . rand); # string

my $sth2 = $dbh->prepare(q{
    SELECT * FROM utf8table
});
$sth2->execute;

my $rv = $sth2->fetchall_arrayref;
print Dumper $rv;

for (@$rv) {
    print encode_utf8($_->[0]), $/;
}

$dbh->disconnect;

exit;
__END__
実行結果
$VAR1 = [
          [
            "\x{3044}\x{308d}\x{306f}0.052142747285874"
          ],
          [
            "\x{3044}\x{308d}\x{306f}0.87866795396349"
          ],
          [
            "\x{3044}\x{308d}\x{306f}0.85588866665876"
          ],
          [
            "\x{3044}\x{308d}\x{306f}0.473092086686851"
          ]
        ];
いろは0.052142747285874
いろは0.87866795396349
いろは0.85588866665876
いろは0.473092086686851

めでたしめでたし。