2011-03-08 14 views
6

Oracle arka uçlu (OCI8 işlevleri) PHP uygulamalı bir uygulama yapıyorum. Uygulama, Oracle 10g XE ile geliştirildi ve müşterinin sahip olduğu herhangi bir sürümde konuşlandırıldı.CHAR semantics ve ORA-01461

uygulama tek baytlık metin (ISO-8859-15) kolları ve Oracle XE Batı Avrupa baskısında karşı gelişen ederken herhangi bir sorun olmadı. Ancak, yakın zamanda Universal sürümünü yükledim ve ASCII olmayan karakterlerle geniş dizeleri eklerken sorun yaşıyorum. Bu versiyon NLS_CHARACTERSET = AL32UTF8; Uygulamamın WE8ISO8859P15 Oracle kullanmasını sağladığımdan, giriş verilerimi ISO-8859-15'ten UTF-8'e dönüştürüyor (bu da gayet iyi). Ancak bazı boyut denetimlerinin yanlış gittiği görülüyor: 1500 karakterli bir dize (ISO-8889-15'te 1500 bayt, UTF-8'de 4500 bayt) bir VARCHAR2(4000 CHAR) sütununda taşıyor gibi görünüyor.

Ben bu test tablo oluşturduk:

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) 
); 
sorun bu kodla yeniden olabilir

:

<?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'])); 
} 

... tetikler:

Uyarı: oci_execute(): ORA-01461: Ürün detayları Ürün numarası Dökümanlar LONG para insertarlo en una columna UZUN

4001 karakter dizisi eklemeye çalıştığımda aldığım hata da aynı. Bunun yerine €€€ ait xxx... eklemek eğer olmaz ve ben UTF-8 olarak benim komut kaydetmek durumunda ne ve bu şekilde bağlamak değildir:

<?php 
$connection = oci_connect(DB_USER, DB_PASS, DB_CONN_STRING, 'AL32UTF8'); 

[Güncelleme: Testim kusurlu oldu . UTF-8 kullanmak ORA-01461'den kaçınmaz]

Bu sorunu nasıl geçersiz kılabilirim? NLS_CHARACTERSET veritabanı parametresi, numaralı telefonu denetlediğim ve uygulamanızı UTF-8 olarak değiştirdiğim bir şey değil, başka sorunlara da neden olabilir (neredeyse tüm müşterilerimiz tek bayt veritabanlarına sahiptir).

cevap

9

Bu muhtemelen, VARCHAR2 yerine CLOB kullanmak istemediğiniz sürece çalışmayacağınız bir şey değildir.

Oracle'da, bir sütunu bildirdiğinizde, varsayılan değer bayt uzunluğunda semantik kullanmaktır. Böylece bir VARCHAR2 (100), örneğin, 100 bayt depolama alanı ayırır. ISO 8859-1 gibi bir tek baytlık karakter kümesi kullanıyorsanız, her karakter 1 bayt depolama alanı gerektirir, bu nedenle bu, aynı zamanda 100 karakter için yer ayırır. Ancak, UFT-8 gibi çok baytlı bir karakter kümesi kullanıyorsanız, her karakter 1 ve 4 bayt depolama alanı gerektirebilir. Bu nedenle, VARCHAR2 (100), verilere bağlı olarak yalnızca 25 karakterlik veri saklayabilir (genellikle İngilizce karakterler 1 bayt gerektirir, Avrupa karakterleri genellikle 2 bayt gerektirir ve Asya karakterleri genellikle 3 bayt gerektirir).

Oracle'a, bir ISO-8859-1 veritabanından bir UTF-8 veritabanına taşınırken önerdiğim normalde karakter uzunluğundaki semantiği kullanmasını söyleyebilirsiniz. Bir sütun VARCHAR2 (100 CHAR) bildirirseniz, Oracle 100 bayt veya 400 bayt olmaktan bağımsız olarak 100 karakter için yer ayırır.Ayrıca, varsayılan değiştirmeyi (yeni DDL için) değiştirmek için NLS_LENGTH_SEMANTICS parametresini CHAR olarak ayarlayabilirsiniz, böylece VARCHAR2 (100) 100 bayt yerine 100 karakter depolama alanı ayırır.

Ne yazık ki sizin için bir Oracle VARCHAR2 (PL/SQL motoru yerine SQL motoru bağlamında) üzerindeki sınır 4000 bayttır. Dolayısıyla, bir sütun VARCHAR2 (4000 CHAR) bildirseniz bile, aslında 1000 karakterden az olabilen 4000 baytlık veri eklemekle sınırlı olacaksınız. Örneğin, AL32UTF8 karakter kümesini kullanarak bir veritabanında, bir sütun VARCHAR2 (4000 CHAR) ama depolama 2 bayt gerektirir bir karakter ekleyerek gerçekten verilerin 4000 karakterler eklemek olamayacağını göstermektedir bildirebilirsiniz

SQL> create table foo (
    2 col1 varchar2(4000 char) 
    3 ); 

Table created. 

SQL> insert into foo values(rpad('abcde', 4000, unistr('\00f6'))); 

1 row created. 

SQL> ed 
Wrote file afiedt.buf 

    1* insert into foo values(rpad('abcde', 6000, unistr('\00f6'))) 
SQL>/

1 row created. 

SQL> select length(col1), lengthb(col1) 
    2 from foo; 

LENGTH(COL1) LENGTHB(COL1) 
------------ ------------- 
     2003   4000 
     2003   4000 

4000 karakterden oluşan UTF-8 verisi depolamanız gerekiyorsa, bir CLOB'a taşınmayı gerektirecek 16000 bayta sahip olabilecek bir veri türüne ihtiyacınız olacaktır.

+0

Haklısınız, UTF-8 test komut dosyasında bir hata oluştu: ORA-01461'i de tetikliyor. VARCHAR2 (4000 CHAR) '4000 * bayttan fazla * tutamayacak gibi görünüyor. Sütun boyutunu düşürüp düşürmeyeceğinizi ya da 'CLOB '' a geçip geçmeyeceğimi inceleyeceğim. –

+0

Bazı referanslar buldum: "VARCHAR2 sütunu olan bir tablo oluşturduğunuzda, VARCHAR2 sütunu için 1 ve 4000 ** bayt ** arasında bir maksimum dize uzunluğunu (bayt veya karakter olarak) belirtirsiniz." - http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/datatype.htm#sthref3780 –

+1

Alternatif bir sabit bayt karakter takımı kullanarak sorunu en aza indirgeyebilirsiniz. Örneğin JA16SJIS, Japonca karakterler için iki bayt kullanır ve TH8TISASCII, tek baytlık bir Thai karakter kümesidir –

İlgili konular