2012-11-23 8 views
8

Ich benutze Oracle 11g (auf Red Hat). Ich habe einfach normale Tabelle mit XMLType Säule:Seltsame Oracle XMLType.getClobVal() Ergebnis

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

Verwenden von Oracle SQL Developer (unter Windows) ich:

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

Es funktioniert. Ich bekomme eine Zelle. Ich kann die gesamte XML-Datei doppelklicken und herunterladen.

Dann habe ich versucht, das Ergebnis als CLOB zu erhalten:

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

Es funktioniert. Ich bekomme eine Zelle. Ich kann doppelklicken und den ganzen Text sehen und kopieren. Aber es gibt ein Problem. Wenn ich es in die Zwischenablage kopiere, bekomme ich nur die ersten 4000 Zeichen. Es scheint, dass es 0x00 Zeichen an Position 4000 gibt und der Rest von CLOB wird nicht kopiert.

Um dies zu bestätigen, schrieb ich check in 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)); 

Reader liefert volle XML aber meine Ausnahme ausgelöst wird, weil es an der Position Null-Zeichen 4000. ich dieses einzelne Byte entfernen könnte, aber dies eher sein würde seltsame Problemumgehung.

Ich benutze VARCHAR2 nicht dort, aber vielleicht hängt dieses Problem irgendwie mit VARCHAR2 Begrenzung (4000 Bytes) zusammen? Irgendwelche anderen Ideen? Ist das ein Oracle Bug oder fehlt mir etwas?

-------------------- -------------------- bearbeiten

Wert mit folgenden gespeicherten Prozedur wurde eingefügt:

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; 

Java-Code verwendet, es zu nennen:

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

-------------------- bearbeiten. EINFACHER TEST --------------------

Ich werde alles verwenden, was ich aus Ihren Antworten gelernt habe. Erstellen Sie die einfachste Tabelle:

create table T1 (P XMLTYPE); 

Bereiten Sie zwei CLOBs mit XMLs vor. Zuerst mit Nullzeichen, zweites ohne.

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>'; 

Überprüfen Sie, ob null im ersten CLOB und nicht in der zweiten:

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

Wir werden wie erwartet erhalten:

14 
0 

Versuchen erste CLOB in XMLTYPE einzufügen. Es wird nicht funktionieren. Es ist nicht möglich, einen solchen Wert einzufügen:

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

Versuchen zweite CLOB in XMLTYPE einzufügen. Es wird funktionieren:

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

Versuchen Sie, eingefügtes XML in dritten CLOB zu lesen.Es wird funktionieren:

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

Überprüfen Sie, ob dort null ist. Es gibt KEINE null:

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

Es Nähte, dass es keine Null innerhalb Datenbank ist und solange wir in der PL/SQL-Kontext sind, gibt es keine Null. Aber wenn ich versuche folgende SQL in SQL Developer zu verwenden (unter Windows) oder in Java (auf Red Hat EE und tomcat7) bekomme ich null Zeichen an Position 4000 in allen zurück CLOBs:

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

BR, JM

+2

Können Sie schreiben in eine Datei 'utl_file' und sehen, wie die Inhalte aussehen? Können Sie auch versuchen '' XMLType.getClobVal (PROJECT) von PROJECTS auszuwählen; '? (Nichts funktionell anders aber) – Annjawn

+1

Wie wurde die Kolumne bevölkert? Sind Sie sicher, dass das Problem beim Abruf liegt - klingt unwahrscheinlich, wenn verschiedene Kunden dasselbe sehen. Sie können auch eine Teilzeichenfolge des Werts auswählen und prüfen, ob das Nullzeichen noch vorhanden ist. –

+0

Ich habe utlfile.sql und prvtfile.plb ausgeführt, aber ich kann immer noch nicht utl_file (ORA-06521: PL/SQL: Fehler-Mapping-Funktion), sorry. – Mikosz

Antwort

6

seine nicht ein Oracle-Fehler (es speichert und ruft die \ 0 gut. es ist ein Client/Windows-Bug (Verschiedene Clients verhalten sich anders in Bezug auf "NUL" als Fenster) hat

chr (0) ist nicht ein gültiges Zeichen in Nicht-Blobs wirklich (ich bin neugierig, wie Sie jemals den XMLType erhalten, um es in erster Linie zu akzeptieren, da es normalerweise nicht analysieren würde.)

\ 0 wird in C verwendet, um das Ende einer Zeichenfolge (NUL-Terminator) zu bezeichnen, und einige GUIs würden die Verarbeitung der Zeichenfolge an diesem Punkt beenden. Zum Beispiel:

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

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

SQL> 

noch nicht Kröte kläglich dazu: TOAD

SQL-Entwickler besser ab, wie Sie es sehen können:

SQL Developer

aber wenn Sie es kopieren, die Zwischenablage wird nur bis zum Null-Zeichen kopiert. Dieser Copy-Paste-Fehler ist zwar kein SQL-Entwicklerfehler, aber ein Problem mit der Windows-Zwischenablage, das es NUL nicht erlaubt, korrekt einzufügen.

sollten Sie nur replace(T1.PROJECT.getClobVal(), chr(0), null) um dies zu umgehen, wenn sql Entwickler/Windows-Zwischenablage verwenden.

+0

Vielen Dank für Ihre Antwort. Natürlich ist die Zwischenablage ein Problem von Windows, aber das ist nicht das Hauptproblem, es ist nur eine Möglichkeit, es zu testen. Ich will wissen, warum null da ist :). Und ich denke, das ist kein Problem des Kunden. Wenn ich einzelne Zellen aus dieser Tabelle (mit SQL Developer oder Blob in Java) herunterlade, gibt es kein Nullzeichen. Es erscheint nur, wenn ich PROJECT.getClobVal() verwende (sowohl in SQL Developer als auch in Java). Für mich bedeutet das, dass getClobVal() ein Nullzeichen in Position 4000 des Ergebnisses einfügt. – Mikosz

+2

Nein, es tut dies nicht (oder sollte nicht) und wenn es in jedem einzelnen LOB ist, würde ich empfehlen, dass Sie eine SR mit Oracle einreichen. Ich benutze XMLType ausgiebig für Dateien mit einer Größe von mehr als 1 MB und es wurde nie ein chr (0) drin gelassen (10.2.0.4 + 11.2.0.2). – DazzaL

+0

Danke. Ich benutze auch 11.2.02 (Express Edition). Ich habe meinen Beitrag mit dem einfachsten Test bearbeitet. Es scheint, dass dieses Problem bei jedem getClobVal() - Ergebnis auftritt, wenn es außerhalb von PL/SQL übertragen wird. – Mikosz

1

Einfach genug, um zu überprüfen, ob es der .getClobVal() Anruf ist oder nicht - führt einen INSTR Test in PL/SQL (nicht Java) auf dem resultierenden CLOB zu sehen, ob die CHR(0) existiert oder nicht.

Wenn nicht, dann würde ich den Finger auf Ihre Oracle-Client-Installation zeigen.

+0

Danke. Sie haben Recht, dass es in PL/SQL keine Null gibt. Es erscheint, wenn das Ergebnis nach außen übertragen wird. Es ist seltsam, weil ich zwei verschiedene Clients verwende (SQL Developer unter Windows und Java unter Red Hat). – Mikosz

+2

Sie könnten unter einem JDBC-Fehler leiden; Da beide Clients Java-basiert sind. – Ben

3

Ich habe auch das gleiche Problem genau wie von Mikosz beschrieben (sehen ein zusätzliches 'NUL' Zeichen um das 4000. Zeichen bei der Ausgabe meiner XMLType-Wert als Clob). Während ich in SQLDeveloper herumspielte, bemerkte ich eine interessante Problemumgehung. Ich habe versucht, die Ausgabe meines XMLType zu sehen, aber ich war es leid, zum 4000. Zeichen zu scrollen, also begann ich, die Clob-Ausgabe in einen substr zu schreiben (...). Zu meiner Überraschung verschwand das Thema tatsächlich. Ich habe dies in meine Java-App integriert und bestätigt, dass das Problem nicht mehr vorhanden war und mein Clob ohne das zusätzliche Zeichen abgerufen werden konnte. Ich weiß, dass dies keine ideale Problemumgehung ist, und ich bin mir immer noch nicht sicher, warum es funktioniert (würde mich freuen, wenn mir jemand das erklären könnte), aber hier ist ein abgekürztes Beispiel dafür, was ich gerade funktioniert habe:

// 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

Es ist auch erwähnenswert, dass wir die XMLType-Spalte an einigen Stellen verwenden. An den Orten, an denen wir ein Schema (strukturiertes XML) registriert haben, sehe ich dieses Problem nicht. Für die XMLType-Spalte, die kein registriertes Schema verwendet, wird dieses Problem angezeigt. – Mark

+0

Vielen Dank für Ihren Vorschlag. Es hat mein Problem auch gelöst. Dies war der einzige Ort, an dem ich eine passende Lösung finden konnte. –

3

Fehler: 14781609 XDB: XMLType.getclobval() gibt einen temporären LOB zurück, wenn XML in einem CLOB gespeichert wird. Fehlerbehebung in Patchset 11.2.0.4

und eine andere Lösung wenn als Blob lesen, dann kein Fehler wie

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