2012-11-23 29 views
8

Używam Oracle 11g (w Red Hat). Mam proste regularne tabelę z kolumny XMLType:Dziwne Oracle XMLType.getClobVal() wynik

CREATE TABLE PROJECTS 
(
    PROJECT_ID NUMBER(*, 0) NOT NULL, 
    PROJECT SYS.XMLTYPE, 
); 

Używanie Oracle SQL Developer (Windows) robię:

select T1.PROJECT P1 from PROJECTS T1 where PROJECT_ID = '161'; 

to działa. Dostaję jedną komórkę. Mogę dwukrotnie kliknąć i pobrać cały plik XML.

Potem starał się prowadzić jak CLOB:

select T1.PROJECT.getClobVal() P1 from PROJECTS T1 where PROJECT_ID = '161'; 

to działa. Dostaję jedną komórkę. Potrafię podwójnie kliknąć i zobaczyć cały tekst i skopiować go. Ale jest problem. Po skopiowaniu do schowka otrzymuję tylko pierwsze 4000 znaków. Wydaje się, że na pozycji 4000 znajduje się znak 0x00, a reszta elementu CLOB nie jest kopiowana.

Aby to potwierdzić, napisałem czek w Java:

// ... create projectsStatement 
Reader reader = projectsStatement.getResultSet().getCharacterStream("P1"); 
BufferedReader bf = new BufferedReader(reader); 
char buffer[] = new char[ 1024 ]; 
int count = 0; 
int globalPos = 0; 
while ((count = bf.read(buffer, 0, buffer.length)) > 0) 
    for (int i = 0; i < count; i++, globalPos++) 
     if (buffer[ i ] == 0) 
      throw new Exception("ZERO at " + Integer.toString(globalPos)); 

czytnik powraca pełną XML ale mój jest wyjątek, ponieważ nie jest null postać w pozycji 4000. mogę usunąć ten jeden bajt, ale to byłoby raczej dziwne obejście.

Nie używam VARCHAR2, ale może ten problem jest w jakiś sposób związany z ograniczeniem VARCHAR2 (4000 bajtów)? Jakieś inne pomysły? Czy to jest błąd Oracle, czy też czegoś mi brakuje?

-------------------- Edycja --------------------

Wartość wstawiono używając następującą procedurę przechowywaną:

create or replace 
procedure addProject(projectId number, projectXml clob) is 
    sqlstr varchar2(2000); 
begin 

    sqlstr := 'insert into projects (PROJECT_ID, PROJECT) VALUES (:projectId, :projectData)'; 
    execute immediate sqlstr using projectId, XMLTYPE(projectXml); 

end; 

kodu Java zwykli nazywać ją:

try (CallableStatement cs = connection.prepareCall("{call addProject(?,?)}")) 
{ 
    cs.setInt("projectId", projectId); 
    cs.setCharacterStream("projectXml", new StringReader(xmlStr) , xmlStr.length()); 
    cs.execute(); 
} 

-------------------- Edycja. PROSTY TEST --------------------

Wykorzystam wszystko, czego nauczyłem się z twoich odpowiedzi. Utwórz najprostszy tabelę:

create table T1 (P XMLTYPE); 

Przygotuj dwa obiekty CLOB z plikami XML. Najpierw z charakterem zerowym, drugi bez.

declare 
    P1 clob; 
    P2 clob; 
    P3 clob; 
begin 

    P1 := '<a>'; 
    P2 := '<a>'; 
    FOR i IN 1..1000 LOOP 
    P1 := P1 || '' || chr(0); 
    P2 := P2 || ''; 
    END LOOP; 
    P1 := P1 || '</a>'; 
    P2 := P2 || '</a>'; 

Sprawdź, czy null jest w pierwszej CLOB, a nie w drugim:

DBMS_OUTPUT.put_line(DBMS_LOB.INSTR(P1, chr(0))); 
DBMS_OUTPUT.put_line(DBMS_LOB.INSTR(P2, chr(0))); 

Będziemy się zgodnie z oczekiwaniami:

14 
0 

próby wstawienia pierwszego CLOB do XMLType. To nie zadziała. Nie można wstawić takiej wartości:

insert into T1 (P) values (XMLTYPE(P1)); 

Spróbuj wstawić drugi obiekt CLOB do XMLTYPE. to będzie działać:

insert into T1 (P) values (XMLTYPE(P2)); 

spróbować odczytać wprowadzone dane XML do trzeciego CLOB.Będzie działać:

select T.P.getClobVal() into P3 from T1 T where rownum = 1; 

Sprawdź, czy jest pusty. NIE ma wartość null:

DBMS_OUTPUT.put_line(DBMS_LOB.INSTR(P3, chr(0))); 

szwy, że nie ma zerowy wewnątrz bazy danych i jak długo jesteśmy w kontekście PL/SQL, nie ma wartość null. Ale gdy próbuję użyć następujących SQL w SQL Developer (w systemie Windows) lub w Java (Red Hat EE i Tomcat7) otrzymuję znak null w pozycji 4000 we wszystkich zwróconych CLOB:

select T.P.getClobVal() from T1 T; 

Br JM

+2

można zapisywać do pliku przy użyciu 'utl_file' i zobaczyć, jak zawartość wygląda? Czy możesz również spróbować 'select XMLType.getClobVal (PROJECT) from PROJECTS;'? (Nic funkcjonalnie innego) – Annjawn

+1

Jak było wypełnione columm? Czy na pewno problem polega na pobieraniu - brzmi to nieprawdopodobnie, jeśli różni klienci widzą to samo. Możesz także wybrać podzwanie wartości i sprawdzić, czy znak null nadal tam jest. –

+0

Uruchomiłem utlfile.sql i prvtfile.plb, ale nadal nie mogę użyć pliku utl_file (ORA-06521: PL/SQL: funkcja mapowania błędów), przepraszam. – Mikosz

Odpowiedz

6

jej nie jest bug Oracle (sklepy IT i pobiera \ 0 dobrze. swój błąd, klient/okna (Różni klienci zachowują się inaczej w odniesieniu do "nul" podobnie jak w systemie Windows)

Chr (0) nie jest poprawna postać w non-blobs naprawdę (jestem ciekawa, jak możesz zdobyć XMLType, aby zaakceptować go w pierwszej kolejności, tak jak zwykle nie parsowałoby się)

\ 0 jest używane w C dla oznaczenia końca łańcucha (terminator NUL) i niektóre GUI przestaną przetwarzać ciąg znaków w tym punkcie. Na przykład:

![SQL> select 'IM VISIBLE'||chr(0)||'BUT IM INVISIBLE' 
    2 from dual 
    3/

'IMVISIBLE'||CHR(0)||'BUTIM 
--------------------------- 
IM VISIBLE BUT IM INVISIBLE 

SQL> 

jeszcze ropucha nie zdało egzaminu w tej sprawie: TOAD

opłaty SQL Developer lepiej, jak można go zobaczyć:

SQL Developer

ale jeśli to kopia clipboard skopiuje je tylko do znaku nul. ten błąd wklejania kopii nie jest jednak wadą deweloperów SQL, jest to problem ze schowkiem Windows, który nie pozwala NUL poprawnie wklejać.

powinieneś po prostu replace(T1.PROJECT.getClobVal(), chr(0), null) zaokrąglić to przy użyciu sql developer/windows clipboard.

+0

Dziękuję za odpowiedź. Oczywiście schowek jest problemem Windowsa, ale to nie jest główny problem, to tylko sposób na przetestowanie go. Chcę wiedzieć, dlaczego jest null :). I myślę, że to nie jest problem klienta. Podczas pobierania pojedynczej komórki z tej tabeli (przy użyciu SQL Developer lub Blob w Javie) nie ma pustej litery. Pojawia się tylko wtedy, gdy używam PROJECT.getClobVal() (zarówno w SQL Developer, jak iw Javie). Tak więc dla mnie to szwy, że getClobVal() wstawia znak null na pozycji 4000 jego wyniku. – Mikosz

+2

nie, nie robi tego (lub nie powinien), a jeśli tak, to na każdym pojedynczym LOB, polecam złożyć SR z Oracle. W dużym stopniu korzystam z XMLType na plikach znacznie większych niż 1MB i nigdy nie upuszczałem tam chr (0) (10.2.0.4 + 11.2.0.2). – DazzaL

+0

Dzięki. Używam również 11.2.02 (edycja ekspresowa). Redagowałem mój post najprostszym testem. Wydaje się, że problem pojawia się przy każdym wyniku getClobVal(), gdy jest przenoszony poza PL/SQL. – Mikosz

1

dość łatwe do sprawdzenia, czy jest to rozmowa .getClobVal() czy nie - wykonać test w PL/SQL (nie Java) INSTR na wypadkowej CLOB aby sprawdzić, czy CHR(0) istnieje, czy nie.

Jeśli nie, to wskazałbym palcem na instalację klienta Oracle.

+0

Dzięki. Masz rację, że nie ma zerowej wartości w PL/SQL. Pojawia się, gdy wynik zostanie przeniesiony na zewnątrz. To dziwne, ponieważ korzystam z dwóch różnych klientów (SQL Developer w Windows i Java w Red Hat). – Mikosz

+2

Możesz cierpieć na błąd JDBC; widząc, jak obaj twoi klienci są opartymi na Javie. – Ben

3

Występowałam również w tym samym problemie dokładnie tak, jak opisał to Mikosz (widząc dodatkowy znak "NUL" wokół 4000. znaku podczas wyprowadzania mojej wartości XMLType jako Clob). Podczas zabawy w SQLDeveloper zauważyłem interesujące obejście. Próbowałem zobaczyć wyjście z mojego XMLType, ale byłem zmęczony przewijaniem do 4000th znaków, więc zacząłem owijać wyjście Clob w substr (...). Ku mojemu zdziwieniu, sprawa właściwie zniknęła. Włączyłem to do mojej aplikacji Java i potwierdziłem, że problem już nie występował i mój Clob mógł zostać odzyskany bez dodatkowego znaku. Wiem, że to nie jest idealne rozwiązanie, i nadal nie jestem pewien, dlaczego to działa (chciałbym, aby ktoś mógł mi to wyjaśnić), ale oto skrócony przykład tego, co aktualnie pracuję:

// Gets the xml contents 
String sql = "select substr(x.xml_content.getClobVal(), 0) as xml_content from my_table x"; 
ps = con.prepareStatement(sql); 
if(rs.next()) { 
    Reader reader = new BufferedReader(rs.getCharacterStream("xml_content")); 
    ... 
} 
+0

Warto również wspomnieć, że używamy kolumny XMLType w kilku miejscach. W miejscach, w których zarejestrowaliśmy schemat (uporządkowany xml), nie widzę tego problemu. W przypadku kolumny XMLType, która nie używa zarejestrowanego schematu, widzimy ten problem. – Mark

+0

Bardzo dziękuję za sugestię. To także rozwiązało mój problem. To było jedyne miejsce, w którym mogłem znaleźć odpowiednie rozwiązanie. –

3

Błąd: 14781609 XDB: XMLType.getClobval() zwraca tymczasowy obiekt LOB, gdy plik XML jest zapisany w pliku CLOB. poprawka w zestawie poprawek 11.2.0.4

i inne rozwiązanie jeśli czytać jak kropelka, to nie błąd jak

T1.PROJECT.getBlobVal(nls_charset_id('UTF8'))