Oracleバックエンド(OCI8機能)を使用してPHP駆動型アプリケーションを保守します。このアプリケーションはOracle 10g XEで開発され、顧客が所有するバージョンに展開されます。CHARセマンティクスとORA-01461
アプリケーションでは、シングルバイトテキスト(ISO-8859-15)が処理されており、西ヨーロッパの版のOracle XEに対して開発中に問題は発生しませんでした。しかし、私は最近ユニバーサル版をインストールしました。非ASCII文字を含む大きな文字列を挿入する際に問題があります。このバージョンはNLS_CHARACTERSET = AL32UTF8
を設定します。私のアプリケーションではWE8ISO8859P15
を使用しているので、Oracleは入力データをISO-8859-15からUTF-8にサイレント変換します(これは問題ありません)。しかし、特定のサイズチェックが間違っているようです:1500 €
文字(ISO-8889-15で1500バイト、UTF-8で4500バイト)の文字列がVARCHAR2(4000 CHAR)
カラムをオーバーフローしているようです。
私は、このテストテーブルを作成しました:
CREATE TABLE FOO (
FOO_ID NUMBER NOT NULL ENABLE,
DATA_BYTE VARCHAR2(4000 BYTE),
DATA_CHAR VARCHAR2(4000 CHAR),
CONSTRAINT FOO_PK PRIMARY KEY (FOO_ID)
);
問題は、このコードで再現でき
:
<?php
$connection = oci_connect(DB_USER, DB_PASS, DB_CONN_STRING, 'WE8ISO8859P15');
if(!$connection){
$e = oci_error();
die(htmlspecialchars($e['message']));
}
$id = 1;
$data = str_repeat('€', 1500);
$sql = 'INSERT INTO FOO (FOO_ID, DATA_CHAR) ' .
'VALUES (:id, :data)';
$res = oci_parse($connection, $sql);
if(!$res){
$e = oci_error();
die(htmlspecialchars($e['message']));
}
if(!oci_bind_by_name($res, ':id', $id)){
$e = oci_error();
die(htmlspecialchars($e['message']));
}
if(!oci_bind_by_name($res, ':data', $data)){
$e = oci_error();
die(htmlspecialchars($e['message']));
}
if(!oci_execute($res, OCI_COMMIT_ON_SUCCESS)){
$e = oci_error();
die(htmlspecialchars($e['message']));
}
...トリガー:
警告:oci_executeを(): ORA-01461:ソロ・プードゥ・エヴァンジャ・アン・ヴァール ロング・パラ・インサート・アンド・コラム LONG
4001文字列を挿入しようとしたときと同じエラーです。私が代わりに€€€
のxxx...
を挿入する場合には発生しません、それは私がUTF-8として私のスクリプトを保存した場合に起こり、そのように接続していない:
<?php
$connection = oci_connect(DB_USER, DB_PASS, DB_CONN_STRING, 'AL32UTF8');
[更新:私のテストには欠陥でした。 UTF-8を使用しても回避できないORA-01461
この問題をどのように解決できますか? NLS_CHARACTERSETデータベースパラメータは私が制御しているものではありません私のアプリケーションをUTF-8に切り替えると他の問題が発生する可能性があります(ほぼすべてのお客様がシングルバイトデータベースを持っています)。
私のUTF-8テスト・スクリプトでエラーが発生しました。これはORA-01461もトリガーします。 'VARCHAR2(4000 CHAR)'は4000バイト以上を保持できないようです。私は列のサイズを下げるか、 'CLOB'に切り替えるかについて調べます。 –
「VARCHAR2列の表を作成するときは、VARCHAR2列の最大文字列長(バイトまたは文字数)を1〜4000バイト**に指定します。 - http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/datatype.htm#sthref3780 –
代替固定バイト文字セットを使用すると、問題を最小限に抑えることができます。たとえば、JA16SJISは日本語文字に2バイトを使用し、TH8TISASCIIは1バイトのタイ語文字セット –