DBD::SQLite 1.32_02

今回の更新ではRTreeのサポートが入ったほか、半年以上前から実装は済んでいたものの表に出していなかった、DBD::SQLiteのバインド値が数値だった場合に不要にクォートされてしまうため関数の戻り値などとマッチできなかった問題への対策が入っています。

具体的にいうと、従来はこんなテストコードがあった場合、

use strict;
use warnings;
use DBI;
use Test::More;

my $dbh = DBI->connect('dbi:SQLite::memory:');
$dbh->do('create table foo (id integer, bar text)');
$dbh->do('insert into foo values (?, ?)', undef, 1, 'odd');
$dbh->do('insert into foo values (?, ?)', undef, 2, 'even');
$dbh->do('insert into foo values (?, ?)', undef, 3, 'odd');
$dbh->do('insert into foo values (?, ?)', undef, 4, 'even');
$dbh->do('insert into foo values (?, ?)', undef, 5, 'odd');

my $res = $dbh->selectall_arrayref('
  select bar from foo group by bar having count(*) > ?', undef, 1);

TODO: {
  local $TODO = 'long-standing bug';
  is @$res => 2;
}

done_testing;

実際に実行されるSQL文は

select bar from foo group by having count(*) > "1";

のようになってしまい、数値と文字列のミスマッチが起こって検索結果が0になってしまっていたのですが、1.32_02からは、このように書くことで、バインド値が数値かどうかを判定して、数値の場合はクォートしない、という処理が行われるようになります。

$dbh->{sqlite_see_if_its_a_number} = 1;  # ここ

$res = $dbh->selectall_arrayref('
  select bar from foo group by bar having count(*) > ?', undef, 1);

is @$res => 2;

done_testing;

なお、このアトリビュートを設定すると、数値型のカラムの返り値が、小数点の扱いなどの点で従来と微妙に変わることがわかっています(以前は一律で文字列型の場合と同じ値が返っていましたが、sqlite3が返す値により近くなります)。設定や用法によってはテストがこけるなどの問題が起こりえますので、既存のデータベース、既存のアプリケーションで利用される場合は事前に十分な検証をお願いします。