2012-11-23 70 views
8

Oracle 11g(Red Hat上)を使用しています。奇妙なOracle XMLType.getClobVal()結果

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

(Windowsの場合)は、Oracle SQL Developerを使用して、私が行います:それは作品

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

私はXMLType列を持つ単純な正規のテーブルを持っています。私は1つの細胞を得る。 XMLファイル全体をダブルクリックしてダウンロードできます。

は、それから私は、CLOBとして結果を取得しようとした:

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

それは動作します。私は1つの細胞を得る。私はダブルクリックして全体のテキストを見て、それをコピーすることができます。しかし問題がある。クリップボードにコピーすると、最初の4000文字しか得られません。位置4000に0x00文字があり、残りのCLOBはコピーされていないようです。

// ... 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は完全なXMLを返しますが、私の例外が位置4000でのNULL文字がありますので、私はこの1バイトを取り除くことができスローされますが、これはむしろ、次のようになります。

これを確認するために、私はJavaで小切手を書きました奇妙な回避策。

私はVARCHAR2を使用しませんが、おそらくこの問題はVARCHAR2の制限(4000バイト)に関係していますか?他のアイデア?これはOracleのバグですか、何か不足していますか?

--------------------

値次のストアドプロシージャを使用して挿入された:それを呼び出すために使用さ

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コード:

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

-------------------- [編集]を。簡単なテスト--------------------

私はあなたの答えから学んだすべてを使用します。最も簡単なテーブルを作成してください:

create table T1 (P XMLTYPE); 

2つのCLOBをXMLで準備してください。最初にヌル文字で、2番目ではありません。

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

チェックnullが最初CLOBではなく秒1である場合:

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

予想通り我々はなります:

14 
0 

はXMLTYPEに最初のCLOBを挿入するようにしてください。うまくいかないだろう。この値を挿入することはできません。

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

2番目のCLOBをXMLTYPEに挿入してみます。それは動作します:

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

挿入されたXMLを3番目のCLOBに読み込もうとします。それは動作します:

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

ヌルがあるかどうかチェックしてください。これは、データベース内部にはヌルがなく、限り、我々はPL/SQLコンテキスト内にあるように、ヌルがないことを縫い目

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

:NO nullはありません。しかし、私は(Windowsの場合)SQL Developerで次のSQLを使用したり(Red HatのEEとTomcat7上)、Javaで私はすべて返されたCLOB内の位置4000でのNULL文字を取得しようとすると:

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

BR、 JM

+2

のようなエラーがあなたが 'utl_file'を使用してファイルに書き込むことはできませんし、内容がどのように見えるか見ますか? 'プロジェクトからXMLType.getClobVal(PROJECT)を選択することもできますか? ' (何も機能的に違いはありません) – Annjawn

+1

コラムにはどのようにして人が入っていましたか?異なるクライアントが同じことを見ていると、検索で問題が発生する可能性は低いですか?また、値のサブリングを選択し、null charがまだそこにあるかどうかを確認することもできます。 –

+0

utlfile.sqlとprvtfile.plbを実行しましたが、utl_file(ORA-06521:PL/SQL:エラー・マッピング関数)を使用できません。 – Mikosz

答えて

6

そのないのOracleのバグ(その店や\ 0だけで罰金を取得します。そのクライアント/ Windowsのバグ(窓がないように、異なるクライアントが「NUL」に関しては異なる挙動を示す)

CHR(0)ではありません(私はあなたがXMLTypeをどのようにして最初の場所でそれを受け入れるかを尋ねるのが好きです)。

\ 0は、文字列(NULターミネータ)の終わりを示すためにCで使用され、一部のGUIはその時点で文字列の処理を停止します。たとえば、次のように

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

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

SQL> 

まだヒキガエルは、この上で無残に失敗します。あなたはそれを見ることができるよう、よりよい TOAD

SQL Developerの運賃を:

SQL Developer

しかし、あなたはそれをコピーした場合、クリップボードはそれをヌル文字にコピーします。このコピーの貼り付けエラーは、SQLデベロッパーのエラーではなく、NULが正しく貼り付けることを許可していないWindowsクリップボードの問題です。

これは、SQLデベロッパー/ウィンドウのクリップボードを使用している場合には、これをラウンドするためにはちょうどreplace(T1.PROJECT.getClobVal(), chr(0), null)です。 CHR(0)が存在するかどうかを確認するために、あなたの結果CLOBにPL/SQL(ないジャワ)でINSTRテストを行う - それは.getClobVal()通話やないかどうか確認するのに十分な簡単

+0

ありがとうございます。もちろん、クリップボードはWindowsの問題ですが、これは主な問題ではなく、単なるテスト方法です。なぜヌルがあるのか​​知りたいのですが:)。私はこれがクライアントの問題ではないと思います。この表から単一のセルをダウンロードすると(SQL Developer、またはJavaのBlobを使用)、ヌル文字はありません。これは、私がPROJECT.getClobVal()を使用すると(SQL DeveloperとJavaの両方で)表示されます。だから、私にとっては、getClobVal()はその結果の位置4000にヌル文字を挿入しています。 – Mikosz

+2

いいえこれは実行されません(そうでない場合)。そうでない場合は、すべての単一LOBで、OracleにSRを登録することをお勧めします。私はXMLTypeを1MB以上のファイルに広範囲に使用しており、そこにchr(0)を落とさなかった(10.2.0.4 + 11.2.0.2)。 – DazzaL

+0

ありがとうございます。私も11.2.02(Express Edition)を使用しています。私は簡単なテストで自分の投稿を編集しました。 PL/SQLの外部に転送されたときに、すべてのgetClobVal()結果に問題が発生するようです。 – Mikosz

1

もしそうでなければ、Oracleクライアントのインストール時に指を指します。

+0

ありがとう。あなたは、PL/SQLのときにnullが存在しないことは間違いありません。結果が外に転送されたときに表示されます。私は2つの異なるクライアント(WindowsではSQL Developer、Red HatではJava)を使用するので、奇妙です。 – Mikosz

+2

あなたはJDBCのバグに悩まされている可能性があります。両方のクライアントがJavaベースであるとみなしています。 – Ben

3

Mikosz(ClobとしてXMLType値を出力するときに4000文字目に余分な 'NUL'文字が表示される)と同じ問題が発生しました。 SQLDeveloperで遊んでいる間、私は興味深い回避策に気づいた。私はXMLTypeの出力を見ようとしていましたが、4000文字目までスクロールするのに疲れていましたので、Clob出力をsubstr(...)にラップし始めました。驚いたことに、この問題は実際には消えてしまいました。私はこれを私のJavaアプリケーションに組み込み、問題がなくなったことを確認し、余分な文字を使わずにClobを取得できるようにしました。私はこれが理想的な回避策ではないことを知っています。なぜそれが働くのか(誰かが私にそれを説明することができれば大好きです)はまだわかりませんが、現在私が働いているものの省略例です:

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

また、XMLType列をいくつかの場所で使用することに言及することは重要です。私たちがスキーマ(構造化XML)を登録した場所では、この問題はありません。登録されたスキーマを使用していないXMLType列については、この問題があります。 – Mark

+0

お寄せいただきありがとうございます。それは私の問題も解決しました。これが私が適切な解決策を見つけることができる唯一の場所でした。 –

3

バグ:14781609 XDB:XMLType.getclobval()は、XMLがCLOBに格納されるときに一時LOBを戻します。パッチセット11.2.0で が修正されました。4

と別のソリューション ブロブとして読めば、その後、

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