DBD::drizzleでMySQLに接続してみる

DrizzleのクライアントをCentOS 5.3に入れてPerl DBIMySQL 5.1につないでみた日記。Drizzleって何?って方はIntroducing the Drizzle Projectをご覧ください。
Drizzle Client & Protocol LibraryからDownloadsと書いてあるリンクをたどって、libdrizzle-0.3.tar.gzをダウンロードする。libdrizzleのビルドは何事もない感じ。

$ tar xvzf libdrizzle-0.3.tar.gz
$ cd libdrizzle-0.3
$ ./configure
$ make
$ sudo make install

CPANからDBD-drizzle-0.100.tar.gzをダウンロードする。ところがビルドしようと素でperl Makefile.PLを叩くと失敗する。

$ tar xvzf DBD-drizzle-0.100.tar.gz
$ cd DBD-drizzle-0.100
$ perl Makefile.PL
Must specify package names on the command line

Cannot find the file 'pkg-config'! Your execution PATH doesn't seem
not contain the path to pkg-config. Resorting to guessed values!
running pkg-config --testdb libdrizzle
--testdb: unknown option
running pkg-config --testhost libdrizzle
--testhost: unknown option
running pkg-config --cflags libdrizzle
Package libdrizzle was not found in the pkg-config search path.
Perhaps you should add the directory containing `libdrizzle.pc'
to the PKG_CONFIG_PATH environment variable
No package 'libdrizzle' found
running pkg-config --libs libdrizzle
Package libdrizzle was not found in the pkg-config search path.
Perhaps you should add the directory containing `libdrizzle.pc'
to the PKG_CONFIG_PATH environment variable
No package 'libdrizzle' found
running pkg-config --nocatchstderr libdrizzle
--nocatchstderr: unknown option
running pkg-config --ssl libdrizzle
--ssl: unknown option
running pkg-config --nofoundrows libdrizzle
--nofoundrows: unknown option
I will use the following settings for compiling and testing:

  libs       (pkg-config) = -lz
  pkg-config (guessed   ) = pkg-config
  testdb     (default   ) = test

To change these settings, see 'perl Makefile.PL --help' and
'perldoc INSTALL'.

Use of uninitialized value in concatenation (.) or string at Makefile.PL line 140.
Using DBI 1.608 (for perl 5.008008 on i386-linux-thread-multi)
installed in /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi/auto/DBI/
Writing Makefile for DBD::drizzle

MySQLの場合はmysql_configコマンドでコンパイルオプションが取れるけど、Drizzleの場合は標準的なpkg-configコマンドを使うらしい。言われるがままにPKG_CONFIG_PATHを設定する。

$ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
$ pkg-config --cflags libdrizzle
-I/usr/local/include
$ pkg-config --libs libdrizzle
-L/usr/local/lib -ldrizzle

なるほど。リトライ。

$ perl Makefile.PL
Must specify package names on the command line

Cannot find the file 'pkg-config'! Your execution PATH doesn't seem
not contain the path to pkg-config. Resorting to guessed values!
running pkg-config --testdb libdrizzle
--testdb: unknown option
running pkg-config --testhost libdrizzle
--testhost: unknown option
running pkg-config --cflags libdrizzle
running pkg-config --libs libdrizzle
running pkg-config --nocatchstderr libdrizzle
--nocatchstderr: unknown option
running pkg-config --ssl libdrizzle
--ssl: unknown option
running pkg-config --nofoundrows libdrizzle
--nofoundrows: unknown option
I will use the following settings for compiling and testing:

  cflags     (pkg-config) = -I/usr/local/include
  libs       (pkg-config) = -L/usr/local/lib -ldrizzle
 -lz
  pkg-config (guessed   ) = pkg-config
  testdb     (default   ) = test

To change these settings, see 'perl Makefile.PL --help' and
'perldoc INSTALL'.

Using DBI 1.608 (for perl 5.008008 on i386-linux-thread-multi)
installed in /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi/auto/DBI/
Writing Makefile for DBD::drizzle

なんかまだ怪しいけど…とりあえず先に進む。

$ make
$ sudo make install

サンプル。

#!/usr/bin/perl

use utf8;
use open ':utf8';
binmode(STDIN, ':utf8');
binmode(STDOUT, ':utf8');
binmode(STDERR, ':utf8');

use strict;
use warnings;
use Encode;
use DBI qw(:sql_types);

my ($dbh);

eval {
    my ($dsn, $sth, $row, $ename);
    
    $dsn = 'DBI:drizzle:scott;port=3306'; # ※1 ※2 ※3 ※4
    # $dsn = 'DBI:mysql:scott;mysql_read_default_file=/etc/my.cnf';
    $dbh = DBI->connect($dsn, 'scott', '',
                        { RaiseError => 1, PrintError => 0, AutoCommit => 0 }); # ※5 ※6 ※7
    
    $sth = $dbh->prepare_cached('insert into emp (empno, ename) values (?, ?)');
    $sth->bind_param(1, 9001, SQL_INTEGER);
    $sth->bind_param(2, 'テスト', SQL_VARCHAR);
    $sth->execute();
    $sth->finish();
    
    $sth = $dbh->prepare_cached('select ename from emp where empno = ?');
    $sth->bind_param(1, 9001, SQL_INTEGER);
    $sth->execute();
    while ($row = $sth->fetch()) {
        $ename = decode_utf8($row->[0]);
        print "$ename\n";
    }
    $sth->finish();
    
    $dbh->rollback();
    $dbh->disconnect();
};
if ($@) {
    print decode_utf8($@);
    if ($dbh) {
        eval {
            $dbh->rollback();
        };
        eval {
            $dbh->disconnect();
        };
    }
    exit(1);
}

動いた。気づいたことをいくつか。

  1. [仕様] UNIX Socket経由の接続はできない。必ずTCP/IP経由
  2. [仕様] DrizzleのTCPポートは4427番なので、MySQLに接続するときは明示的に3306番を指定する
  3. [仕様] UTF-8しかサポートしないので、default-character-setとかset namesしなくていい。ある意味文字化けフリー
  4. [未実装] drizzle_read_default_fileというパラメータでmy.cnfを読み込めるとマニュアルに書いてあったけど、ソースを見たらまだ実装されてなかった
  5. [仕様] 認証機能がないので、パスワードつきのユーザアカウントだと接続できない
  6. [未実装] どうやらRaiseErrorしてくれない
  7. [未実装] どうしてもPrintErrorを抑止できない

なるほど確かにバージョン0.100 (^^;
うまくいったらクライアントの性能を測ってみようと思ったんだけど、まだ早いね。libdrizzleはBSDライセンスというところに魅力を感じる人もいると思うので、今後に期待。

2009/06/21追記

id:tokuhiromさんから「MySQLプロトコルでつなぐ場合はDRIZZLE_CON_MYSQLオプションを指定すべき」というコメントをいただきました。DBD::drizzleのソースを確認してみると、dbdimp.cの1,031行目が実際に接続している箇所のようです。

if (imp_dbh->con != NULL)
{
  imp_dbh->con= drizzle_con_add_tcp(drizzle, NULL, host, portNr, 
                                    user, password, dbname, DRIZZLE_CON_NONE);
}
ret = drizzle_con_connect(imp_dbh->con);

最後の引数で何種類かオプションを指定できるのですが、今のところDBD::drizzleには何も作りこまれていません。試しに直接書きかえて再ビルドしてみました。

if (imp_dbh->con != NULL)
{
  imp_dbh->con= drizzle_con_add_tcp(drizzle, NULL, host, portNr, 
                                    user, password, dbname, DRIZZLE_CON_MYSQL);
}
ret = drizzle_con_connect(imp_dbh->con);

すると、portを指定しなくてもMySQLに接続することができました。

$dsn = 'DBI:drizzle:scott';
# $dsn = 'DBI:drizzle:scott;port=3306';

バージョン1.0までの道のりは長そうです。