2011-03-08 6 views
6

मैं ओरेकल बैकएंड (ओसीआई 8 फ़ंक्शंस) के साथ एक PHP संचालित अनुप्रयोग बनाए रखता हूं। ऐप को ओरेकल 10 जी एक्सई के साथ विकसित किया गया है और ग्राहक के किसी भी संस्करण पर तैनात किया गया है।CHAR semantics और ORA-01461

एप्लिकेशन एकल-बाइट टेक्स्ट (आईएसओ -885 9-15) को संभालता है और ओरेकल एक्सई के पश्चिमी यूरोपीय संस्करण के विरुद्ध विकास करते समय मुझे कोई समस्या नहीं हुई है। हालांकि, मैंने हाल ही में यूनिवर्सल संस्करण स्थापित किया है और गैर-ASCII वर्णों के साथ बड़े तार डालने पर मुझे समस्याएं आ रही हैं। यह संस्करण NLS_CHARACTERSET = AL32UTF8 सेट करता है; चूंकि मेरा ऐप WE8ISO8859P15 का उपयोग करता है ओरेकल चुपचाप मेरे इनपुट डेटा को आईएसओ -885 9-15 से यूटीएफ -8 (जो ठीक है) में परिवर्तित करता है। लेकिन ऐसा लगता है कि कुछ आकार की जांच गलत हो जाती है: 1500 वर्णों (आईएसओ -8889-15 में 1500 बाइट, यूटीएफ -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) 
); 

समस्या इस कोड के साथ reproduced किया जा सकता है:

<?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: sólo puede enlazar un valor लंबे पैरा डालने के लिए una columna लंबे

यह वही त्रुटि है जब मैं 4001 चार स्ट्रिंग डालने का प्रयास करता हूं। अगर मैं €€€ के बजाय xxx... सम्मिलित यह नहीं होता है और अगर मैं के रूप में UTF-8 मेरी स्क्रिप्ट को बचाने ऐसा नहीं होता और इस तरह के रूप कनेक्ट:

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

[अद्यतन: मेरा परीक्षण त्रुटिपूर्ण था । यूटीएफ -8 का उपयोग ओआरए -01461 से बच नहीं है]

मैं इस समस्या को कैसे ओवरराइड कर सकता हूं? NLS_CHARACTERSET डेटाबेस पैरामीटर कुछ ऐसा नहीं है जिसे मैं पर नियंत्रित करता हूं और अपना ऐप यूटीएफ -8 पर स्विच करने की संभावना अन्य समस्याओं का कारण बनता है (लगभग सभी हमारे ग्राहकों के पास एकल बाइट डेटाबेस हैं)।

उत्तर

9

शायद ऐसा कुछ नहीं है जिसे आप तब तक काम कर सकते हैं जब तक कि आप VARCHAR2 की बजाय CLOB का उपयोग नहीं करना चाहते।

ओरेकल में, जब आप कॉलम घोषित करते हैं, डिफ़ॉल्ट बाइट-लम्बाई अर्थशास्त्र का उपयोग करना होता है। तो एक VARCHAR2 (100), उदाहरण के लिए, 100 बाइट स्टोरेज आवंटित करता है। यदि आप आईएसओ 885 9 -1 जैसे एकल-बाइट चरित्र सेट का उपयोग कर रहे हैं, तो प्रत्येक चरित्र को स्टोरेज के 1 बाइट की आवश्यकता होती है, इसलिए यह 100 वर्णों के लिए स्थान आवंटित करता है। लेकिन यदि आप यूएफटी -8 जैसे बहु-बाइट वर्ण सेट का उपयोग कर रहे हैं, तो प्रत्येक चरित्र को स्टोरेज के 1 और 4 बाइट्स के बीच आवश्यकता हो सकती है। इसलिए, डेटा के आधार पर, एक VARCHAR2 (100) केवल 25 वर्णों के डेटा को स्टोर करने में सक्षम हो सकता है (अंग्रेज़ी अक्षरों को आम तौर पर 1 बाइट की आवश्यकता होती है, यूरोपीय अक्षरों को आम तौर पर 2 बाइट की आवश्यकता होती है, और एशियाई पात्रों को आम तौर पर 3 बाइट की आवश्यकता होती है)।

आप ओरेकल को चरित्र लंबाई अर्थशास्त्र का उपयोग करने के लिए कह सकते हैं जो आम तौर पर एक आईएसओ -885 9 -1 डेटाबेस से यूटीएफ -8 डेटाबेस में जाने पर सुझाव देता है। यदि आप एक स्तंभ VARCHAR2 (100 CHAR) घोषित करते हैं, तो ओरेकल 100 वर्णों के लिए स्थान आवंटित करेगा चाहे वह 100 बाइट्स या 400 बाइट्स हो।आप डिफ़ॉल्ट को बदलने के लिए NLS_LENGTH_SEMANTICS पैरामीटर को CHAR पर भी सेट कर सकते हैं (नए डीडीएल के लिए) ताकि एक VARCHAR2 (100) 100 बाइट्स के बजाए स्टोरेज के 100 अक्षरों को आवंटित कर सके।

दुर्भाग्यवश आपके लिए, ओरेकल VARCHAR2 के आकार (पीएल/एसक्यूएल इंजन की बजाय एसक्यूएल इंजन के संदर्भ में) की सीमा 4000 बाइट्स है। तो यदि आप एक स्तंभ VARCHAR2 (4000 CHAR) घोषित करते हैं, तो भी आप वास्तव में डेटा के 4000 बाइट डालने तक ही सीमित रहेंगे जो 1000 वर्णों के रूप में कम हो सकता है। उदाहरण के लिए, एक डेटाबेस AL32UTF8 वर्ण सेट का उपयोग में, मैं एक स्तंभ VARCHAR2 (4000 CHAR) लेकिन एक चरित्र है कि भंडारण की 2 बाइट्स की आवश्यकता है डालने से पता चलता है कि मैं वास्तव में डेटा के 4000 वर्ण सम्मिलित नहीं कर सकते घोषणा कर सकते हैं

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 

यदि आपको यूटीएफ -8 डेटा के 4000 वर्णों को स्टोर करने की आवश्यकता है, तो आपको एक डेटा प्रकार की आवश्यकता होगी जो 16000 बाइट्स को संभाल सके जो सीएलओबी में जाने की आवश्यकता होगी।

+0

आप सही हैं, मुझे मेरी यूटीएफ -8 टेस्ट स्क्रिप्ट में कोई त्रुटि हुई: यह ओआरए -01461 को भी ट्रिगर करता है। ऐसा लगता है कि 'वर्चर 2 (4000 चार्ज)' 4000 * बाइट्स * से अधिक नहीं रख सकता है। मैं अध्ययन करूंगा कि कॉलम आकार को कम करना है या 'सीएलओबी' पर स्विच करना है या नहीं। –

+0

मुझे कुछ संदर्भ मिला: "जब आप VARCHAR2 कॉलम के साथ एक टेबल बनाते हैं, तो आप VARCHAR2 कॉलम के लिए अधिकतम स्ट्रिंग लम्बाई (बाइट्स या वर्णों में) 1 और 4000 ** बाइट्स ** के बीच निर्दिष्ट करते हैं।" - http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/datatype.htm#sthref3780 –

+1

आप वैकल्पिक फिक्स्ड बाइट वर्णमाला का उपयोग करके समस्या को कम करने में सक्षम हो सकते हैं। उदाहरण के लिए जेए 16 एसजेआईएस जापानी अक्षरों के लिए दो बाइट्स का उपयोग करता है, और TH8TISASCII एक सिंगल बाइट थाई वर्णमाला –

संबंधित मुद्दे