2017-02-07 19 views
0

CLOB列を持つ大きな表があります。テキストデータが保存されます。しかし、バイナリ文字列を書いてみたい。私はそのような場合に何らかの問題に直面するだろうか?CLOB列にバイナリ文字列を格納できますか?

EDIT:

移行BLOBに適切ではない - の表は、そのため非常に大きいです。

+0

バイナリデータにBLOB列を使用します。 – Rene

+0

バイナリデータを通常の文字列にエンコードできますが、列の種類を変更することはできません。 –

答えて

3

一般に、あなたはそれを行うことはできません。特にあなたのデータベースがUTF-8(最近のデフォルト)を使用している場合、有効な文字と一致しない多くのビット値があり、挿入と選択時にプレースホルダ(通常は¿)に置き換えられます。

できることは、バイナリデータをBase64文字列としてエンコードすることです。これはテキストのみ(例えばXMLファイルまたはSMTPメール)をサポートして界面でのバイナリデータを転送するための非常に一般的な方法です

テキストとしてあなたのバイナリデータをエンコードするために、この機能を使用します。

FUNCTION EncodeBASE64(InBlob IN BLOB) RETURN CLOB IS 

    lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX; 
    BlobLen INTEGER := DBMS_LOB.GETLENGTH(InBlob); 
    read_offset INTEGER := 1; 
    warning INTEGER; 

    amount INTEGER := 1440; -- must be a whole multiple of 3 
    -- size of a whole multiple of 48 is beneficial to get NEW_LINE after each 64 characters 
    buffer RAW(1440); 
    res CLOB := EMPTY_CLOB(); 

BEGIN 

    IF InBlob IS NULL OR NVL(BlobLen, 0) = 0 THEN 
     RETURN NULL; 
    ELSIF BlobLen <= 24000 THEN 
     RETURN UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(InBlob)); 
    ELSE 
     -- UTL_ENCODE.BASE64_ENCODE is limited to 32k, process in chunks if bigger 
     LOOP 
      EXIT WHEN read_offset >= BlobLen; 
      DBMS_LOB.READ(InBlob, amount, read_offset, buffer); 
      res := res || UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(buffer));  
      read_offset := read_offset + amount; 
     END LOOP; 
    END IF; 
    RETURN res; 

END EncodeBASE64; 

そして、この関数へBLOBに変換

FUNCTION DecodeBASE64(InBase64Char IN CLOB) RETURN BLOB IS 

    res BLOB; 
    clob_trim CLOB; 

    dest_offset INTEGER := 1; 
    src_offset INTEGER := 1; 
    read_offset INTEGER := 1; 
    ClobLen INTEGER := DBMS_LOB.GETLENGTH(InBase64Char); 

    amount INTEGER := 1440; -- must be a whole multiple of 4 
    buffer RAW(1440); 
    stringBuffer VARCHAR2(1440); 
    -- BASE64 characters are always simple ASCII. Thus you get never any Mulit-Byte character and having the same size as 'amount' is sufficient 

BEGIN 

    IF InBase64Char IS NULL OR NVL(ClobLen, 0) = 0 THEN 
     RETURN NULL; 
    ELSIF ClobLen <= 32000 THEN 
     RETURN TO_BLOB(UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(InBase64Char))); 
    ELSE 
     -- Remove all NEW_LINE from base64 string 
     DBMS_LOB.CREATETEMPORARY(clob_trim, TRUE); 
     LOOP 
      EXIT WHEN read_offset > ClobLen; 
      stringBuffer := REPLACE(REPLACE(DBMS_LOB.SUBSTR(InBase64Char, amount, read_offset), CHR(13), NULL), CHR(10), NULL); 
      DBMS_LOB.WRITEAPPEND(clob_trim, LENGTH(stringBuffer), stringBuffer); 
      read_offset := read_offset + amount; 
     END LOOP; 

     read_offset := 1; 
     ClobLen := DBMS_LOB.GETLENGTH(clob_trim); 
     DBMS_LOB.CREATETEMPORARY(res, TRUE); 
     LOOP 
      EXIT WHEN read_offset > ClobLen; 
      buffer := UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(DBMS_LOB.SUBSTR(clob_trim, amount, read_offset))); 
      DBMS_LOB.WRITEAPPEND(res, DBMS_LOB.GETLENGTH(buffer), buffer); 
      read_offset := read_offset + amount; 
     END LOOP; 
     DBMS_LOB.FREETEMPORARY(clob_trim); 
    END IF; 

    RETURN res;  

END DecodeBASE64; 

オンラインで多くのオンラインBase64デコーダ/エンコーダが見つかり、手順を確認できます。

+0

詳細な回答ありがとうございます。私のデータベースはCP1251を使用していますが、現在はBase64を使用してデータを保存しています。私はいくつかのテストを行いましたが、まだ異常は見られません。 –

関連する問題