perl-DBD-MySQL 3.0007-2.el5でハマった件

Perl DBIのプログラムを書いていて、CentOS 5.3付属のDBD::mysqlをそのまま使ったら困ったという話です。

再現ケース

動く例です。

$sth = $dbh->prepare_cached('select ename from emp where empno = ?');
$sth->bind_param(1, 7788, SQL_INTEGER);
$sth->execute();

動かない例です。bind_param()の引数を7788から-7788にしています。

$sth = $dbh->prepare_cached('select ename from emp where empno = ?');
$sth->bind_param(1, -7788, SQL_INTEGER);
$sth->execute();

すると以下のようなエラーメッセージが出力され、SQLの実行が失敗してしまいます。

DBD::mysql::st execute failed: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version
for the right syntax to use near '' at line 1 at test.pl line 17.

MySQLの一般クエリログを見ると、WHERE句に数値が入っていないことが分かります。

select ename from emp where empno =

解説

これは、SQL_INTEGERに対してマイナスの値をバインドできないというバグです。

2007-1-8 Jim Winstead <jimw@mysql.com> Patrick Galbraith <patg@patg.net> (4.001)
* Fix handling of negative integers bound to a column marked as SQL_INTEGER.
  [rt.cpan.org #18976], patch from Mike Schilli.

このバグ自体はDBD::mysql 4.001で修正されていますが、4.001のリリースは2007年1月でありCentOS 5やRed Hat Enterprise Linux 5には取り込まれていません。そのためディストリビューションをそのまま使っている環境では、現在もこの問題を抱えていることになります。
こういう致命的なバグが2007年まで残っていたのは不思議です。bind_param()を使っている人がほとんどいないのかもしれませんね…。

対処方法

bind_param()を使う場合、DBD::mysqlCPANから最新版を持ってきましょう。