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

[`evernote` not found]
このエントリーをはてなブックマークに追加

ハマったので。

PHP 5.1.6

Oracle 10.2.3

にて。

PDO_OCIでPHPとOracleとを繋いでる環境でエラーじゃないけど、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されてる。

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

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

Oracle:SJIS

PHP:UTF-8

これが原因だった。

OracleはSJISなので、全角文字は2バイト。

PHPはUTF-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から取得してる根っこの部分でSJIS→UTF-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倍してあげれば大丈夫。

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

でわ。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です