Prowadzę aplikację opartą na PHP z zapleczem Oracle (funkcje OCI8). Aplikacja została opracowana przy użyciu Oracle 10g XE i wdrożona w dowolnej wersji posiadanej przez klienta.Semantyka CHAR i ORA-01461
Aplikacja obsługuje tekst jednobajtowy (ISO-8859-15) i nigdy nie miałem problemu z opracowaniem wersji z Europy Zachodniej Oracle XE. Jednak ostatnio zainstalowałem Universal wydanie i mam problemy podczas wstawiania dużych ciągów znaków z znakami spoza ASCII. Ta wersja ustawia NLS_CHARACTERSET = AL32UTF8
; ponieważ moja aplikacja używa WE8ISO8859P15
Oracle po cichu konwertuje moje dane wejściowe z ISO-8859-15 na UTF-8 (co jest w porządku). Wygląda jednak na to, że pewne sprawdzenia rozmiarów się nie udają: ciąg znaków o długości 1500 znaków (€
) (1500 bajtów w ISO-8889-15, 4500 bajtów w UTF-8) wydaje się przepełniać kolumnę VARCHAR2(4000 CHAR)
.
Utworzyłem tę tabelę testową:
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)
);
Problemem może być powielana z tym kodem:
<?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']));
}
... co wyzwala:
Warning: oci_execute(): ORA-01461: sólo puede enlazar un valor LONG para insertarlo en una columna LONG
Jest to ten sam błąd, który pojawia się przy próbie wstawienia ciągu znaków 4001. To nie zdarza się jeśli wstawić xxx...
zamiast €€€
i nie stanie, jeśli mogę zapisać skrypt jako UTF-8 i podłączyć w następujący sposób:
<?php
$connection = oci_connect(DB_USER, DB_PASS, DB_CONN_STRING, 'AL32UTF8');
[Aktualizacja: Moja próba była błędna . Używanie UTF-8 nie omija ORA-01461]
Jak mogę zmienić ten problem? Parametr bazy danych NLS_CHARACTERSET nie jest czymś, co kontroluję , a przełączanie mojej aplikacji na UTF-8 prawdopodobnie spowoduje inne problemy (prawie wszyscy nasi klienci mają bazy danych z jednym bajtem).
Masz rację, wystąpił błąd w skrypcie testowym UTF-8: powoduje on również uruchomienie ORA-01461. Wydaje się, że 'VARCHAR2 (4000 CHAR)' nie może pomieścić więcej niż 4000 * bajtów *. Zbadam, czy obniżyć rozmiar kolumny, czy przełączyć na "CLOB". –
Znalazłem odniesienie: "Gdy tworzysz tabelę z kolumną VARCHAR2, określasz maksymalną długość łańcucha (w bajtach lub znakach) od 1 do 4000 ** bajtów ** dla kolumny VARCHAR2." - http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/datatype.htm#sthref3780 –
Być może uda ci się zminimalizować problem, używając alternatywnego stałego zestawu znaków. Na przykład JA16SJIS używa dwóch bajtów dla znaków japońskich, a TH8TISASCII to jednobajtowy tajski zestaw znaków –