PDO : してログ

まさか、PDO のバグだったとは。

PostgreSQL に格納されたバイナリデータ(bytea)を PDO で取得しようとすると、文字列としてしか取得できないバグがあり、5.2.6 で報告されたのに、5.3.28 でも治っていないようです。 おかげで、急ぎのプロジェクトなのに、かなりの時間をロスしてしまいました。 通常、バイナリデータの取得は、以下のように書きますが、このバグにより「xffd8ffdb00430005030404040....」のような文字列が返ってきます。

$sth = $pgsql->prepare("select id,mime,img from t_image limit 1");
$sth->execute();
$sth->bindColumn('id', $id, PDO::PARAM_INT);
$sth->bindColumn('mime', $mime, PDO::PARAM_STR);
$sth->bindColumn('img', $img, PDO::PARAM_LOB);
if ($sth->fetch(PDO::FETCH_BOUND)) {
	header("Content-Type: {$mime}");
	fpassthru($img);
	exit;
}

PDO を使う限り解決策がないため、ネイティブ系の関数を使うか、文字列をバイナリ列に直すしか無いと思われます。 この文字列をバイナリ列に直すコードは、下記のようなものになります。

$sth = $pgsql->prepare("select id,mime,img from t_image limit 1");
$sth->execute();
$sth->bindColumn('id', $id, PDO::PARAM_INT);
$sth->bindColumn('mime', $mime, PDO::PARAM_STR);
$sth->bindColumn('img', $img, PDO::PARAM_LOB);
if ($sth->fetch(PDO::FETCH_BOUND)) {
	header("Content-Type: {$mime}");
	fgets($img,2);
	$data = fgets($img);
	echo pack('H*',$data);;
	exit;
}

文字列で返る以上、扱うデータ量は倍になりますし、pack という重めの関数を用いなければならないため、速度や効率面ではあまりよろしくありません。 ネイティブ系の関数で書ける場合は、そちらのほうがお勧めです。 なお、fgets($img,2); の部分は先頭に入る「x」の文字を捨てるためで、第2引数が「2」なのは、この関数が第2引数マイナス1バイトを読み込むという仕様のためです。 これに気づくのに、2時間ほど要してしまいました(^_^;)

PHP->PDO->ODBC で Microsoft SQL Server 2005 に接続する場合、バイナリ型があるとメモリを大量に消費してしまうようです。例えば、問い合わせ結果に image型がある場合、2GBのメモリが要求されます。これは、image型の最大容量に等しいサイズです。試しに、image型を2つ持ったテーブルを select してみたところ、4GBのメモリを要求されました(´・ω・`)

Fatal error: Out of memory (allocated 524288) (tried to allocate 4294967295 bytes) in ...