PHP(PDO)+Oracle=too large for buffer and was truncated

ハマったので。

PHP 5.1.6
Oracle 10.2.3
にて。


PDO_OCIでPHPOracleとを繋いでる環境でエラーじゃないけど、Warningが出た。

Warning: PDOStatement::fetch(): column X data was too large for buffer and was truncated to fit it in test.php on line XXX

VARCHAR2のカラムからデータを取得すると出た。
正常にデータが取得出来てるっぽかったけど、おしりの何バイトかが切れてた。

おぉ、trancateされてる。

色々調べてみたところ、全角文字が入ってるとダメだった。

さらに調べてみると、原因が分かった。

OracleSJIS
PHPUTF-8
これが原因だった。


OracleSJISなので、全角文字は2バイト。
PHPUTF-8なので、全角文字は3バイト。


PDO_OCIの場合、テーブルのカラムの型と長さを参照してバッファを決めるようで。

全角文字が入っていた場合、そのバッファが溢れる事があるのです。
なんせ、2バイトだと思っていた全角文字が3バイトだったので。

VARCHAR2(20)のカラムに、全角文字が10文字入っていた場合、SJISならば20バイトなので、OK。
しかし、UTF-8だと30バイトになってしまうので、受け取る側のバッファが溢れてしまう、という事。

対応どうしようか・・・
と考え、
/etc/sysconfig/httpd
をちょっと編集してみた。

# cd /etc/sysconfig/
# vi httpd
export NLS_LANG=Japanese_Japan.UTF8
↓に変更
export NLS_LANG=Japanese_Japan.JA16SJIS

# /etc/rc.d/init.d/httpd restart

Warnningは出なくなったけど、文字化けした。
DBから取得してる根っこの部分でSJISUTF-8の変換をかけようかと考えたのですが、symfony+doctorineという事もあり、断念。

だって、調べるの面倒だから・・・


テーブルのカラム長の定義を1.5倍すれば回避出来るけど、運用案件では無理なので断念。


結果、PDO_OCIのソースをちょっと直して対応する事に。

# cd /usr/local/src
# cd PDO_OCI-1.0
# vi oci_statement.c
510行目付近に有る記述
col->maxlen = data_size;

col->maxlen = data_size*1.5;

# ./configure
# make
# make install

PDOがOracleのテーブルのカラムの長さを取得してる部分で、その長さを1.5倍してあげれば大丈夫。


この対応方法が良いかどうかは疑問が残るが、とりあえずはこれで回避しよう。


でわ。