I maintain a PHP driven application with Oracle backend (OCI8 functions). The app is developed with Oracle 10g XE and deployed on whatever version the customer owns.
The application handles single-byte text (ISO-8859-15) and I've never had any problem while developing against the Western European edition of Oracle XE. However, I've recently installed the Universal edition and I'm having issues when inserting large strings with non-ASCII chars. This version sets NLS_CHARACTERSET = AL32UTF8
; since I my app uses WE8ISO8859P15
Oracle silently converts my input data from ISO-8859-15 to UTF-8 (which is fine). But it seems that certain size checks go wrong: a string with 1500 €
characters (1500 bytes in ISO-8889-15, 4500 bytes in UTF-8) appear to overflow a VARCHAR2(4000 CHAR)
column.
I've created this test table:
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)
);
The problem can be reproduced with this code:
<?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']));
}
... which triggers:
Warning: oci_execute(): ORA-01461: sólo puede enlazar un valor LONG para insertarlo en una columna LONG
It is the same error I get when I try to insert a 4001 char string. It doesn't happen if I insert xxx...
instead of €€€
and it doesn't happen if I save my script as UTF-8 and connect as such:
<?php
$connection = oci_connect(DB_USER, DB_PASS, DB_CONN_STRING, 'AL32UTF8');
[Update: My test was flawed. Using UTF-8 doesn't avoid ORA-01461]
How can I override this problem? The NLS_CHARACTERSET database parameter is not something I control and switching my app to UTF-8 is likely to cause other problems (almost all our customers have single byte databases).