2010-09-27 6 views

Odpowiedz

41

I zostały wdrożone to, aby wysłać e-maile cyrylicy przez mojego serwera MS Exchange.

function to_base64(t in varchar2) return varchar2 is 
begin 
    return utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t))); 
end to_base64; 

Wypróbuj.

UPD: po niewielkiej korekcie wpadłem na to, więc to działa w obie strony teraz:

function from_base64(t in varchar2) return varchar2 is 
begin 
    return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(t))); 
end from_base64; 

Można go sprawdzić:

SQL> set serveroutput on 
SQL> 
SQL> declare 
    2 function to_base64(t in varchar2) return varchar2 is 
    3 begin 
    4  return utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t))); 
    5 end to_base64; 
    6 
    7 function from_base64(t in varchar2) return varchar2 is 
    8 begin 
    9  return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw (t))); 
10 end from_base64; 
11 
12 begin 
13 dbms_output.put_line(from_base64(to_base64('asdf'))); 
14 end; 
15/

asdf 

PL/SQL procedure successfully completed 

upd2: Ok, Oto przykładowa konwersja, która działa dla CLOB Po prostu wymyśliłem. Postaraj się opracować dla swoich plam. :)

declare 

    clobOriginal  clob; 
    clobInBase64  clob; 
    substring  varchar2(2000); 
    n    pls_integer := 0; 
    substring_length pls_integer := 2000; 

    function to_base64(t in varchar2) return varchar2 is 
    begin 
    return utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t))); 
    end to_base64; 

    function from_base64(t in varchar2) return varchar2 is 
    begin 
    return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(t))); 
    end from_base64; 

begin 

    select clobField into clobOriginal from clobTable where id = 1; 

    while true loop 

    /*we substract pieces of substring_length*/ 
    substring := dbms_lob.substr(clobOriginal, 
           least(substring_length, substring_length * n + 1 - length(clobOriginal)), 
           substring_length * n + 1); 
    /*if no substring is found - then we've reached the end of blob*/ 

    if substring is null then 
     exit; 
    end if; 

    /*convert them to base64 encoding and stack it in new clob vadriable*/ 
    clobInBase64 := clobInBase64 || to_base64(substring);   
    n := n + 1; 

    end loop; 

    n := 0; 
    clobOriginal := null; 

    /*then we do the very same thing backwards - decode base64*/ 
    while true loop 

    substring := dbms_lob.substr(clobInBase64, 
           least(substring_length, substring_length * n + 1 - length(clobInBase64)), 
           substring_length * n + 1); 
    if substring is null then 
     exit; 
    end if; 
    clobOriginal := clobOriginal || from_base64(substring); 
    n := n + 1; 
    end loop; 

     /*and insert the data in our sample table - to ensure it's the same*/ 
    insert into clobTable (id, anotherClobField) values (1, clobOriginal); 

end; 
+1

działa całkiem dobrze dla mnie, mimo że dostaję spacje w środku mojego kodowania. Wstawiam przestrzeń wyrażenia regularnego wokół mojego wyniku i działam: regexp_replace (utl_raw.cast_to_varchar2 (utl_encode.base64_encode (utl_raw.cast_to_raw (t))), [[: space:]] * ',' ') – Kirby

+2

Występuje mały błąd w drugiej aktualizacji: Parametr "amount" dla dbms_log.substr powinien być "najmniejszy (substring_length, length (clobInBase64) - (substring_length * n + 1))". Sposób, w jaki został napisany, zwraca wartość ujemną, więc podciąg jest zawsze pusty. – BernardMarx

+1

Kodowanie BASE64 pobiera 3 bajty strumienia wejściowego i konwertuje je na 4 * 3 bajty. Każdy z tych 3 Bajtów jest odwzorowany na 64 różne znaki (a-z, A-Z, 0-9, "+", "/" - stąd otrzymujesz nazwę BASE64). Upewnij się, że wartość substring_length jest wielokrotnością 4 dla 'BASE64_DECODE', resp. cała wielokrotność 3 dla 'BASE64_ENCODE'. Zatem funkcja 'to_base64' może zwrócić nieprawidłowy wynik. –

5
+0

może u proszę mi powiedzieć jak to zrobić dla danych typu BLOB? Otrzymuję wyjątek "Bugger Too small for CLOB to CHAR lub BLOB to RAW conversion (actual 50176, maximum 2000)". – Pradeep

+1

Przepraszam ... Otrzymuję wyjątek "BufferToo mały dla konwersji CLOB na CHAR lub BLOB na RAW (rzeczywisty 50176, maksymalnie 2000)". – Pradeep

+0

Pakiet oracle utl_raw akceptuje tylko wejście varchar2, które jest krótkie, więc domyślam się, że wszystko co możesz zrobić, to podzielić swój obiekt blob na mniejsze części za pomocą pakietu dbms_lob, a następnie przekonwertować każdy z nich za pomocą dostarczonej przeze mnie metody, a następnie skleić je razem w pojedynczym bloku. możesz przy okazji podać kod błędu, który otrzymujesz? –

0

Wszystkie poprzednie posty są poprawne. Jest więcej niż jeden sposób na skórze kota. Oto kolejny sposób, aby zrobić to samo: (tylko zastąpić "what_ever_you_want_to_convert" z łańcucha i uruchomić go w Oracle:

set serveroutput on; 
    DECLARE 
    v_str VARCHAR2(1000); 
    BEGIN 
    --Create encoded value 
    v_str := utl_encode.text_encode 
    ('what_ever_you_want_to_convert','WE8ISO8859P1', UTL_ENCODE.BASE64); 
    dbms_output.put_line(v_str); 
    --Decode the value.. 
    v_str := utl_encode.text_decode 
    (v_str,'WE8ISO8859P1', UTL_ENCODE.BASE64); 
    dbms_output.put_line(v_str); 
    END; 
    /

source

-1

zrobić url_raw.cast_to_raw() wsparcie w oracle 6

1

rozwiązanie z utl_encode.base64_encode i utl_encode.base64_decode mają jedno ograniczenie, działają tylko z ciągami o długości do 32 767 znaków/bajtów. bstacles.

  • Dla BASE64_ENCODE funkcja musi czytać 3 Bytes i przekształcić je. W przypadku znaków wielobajtowych (np. öäüè€ przechowywanych w UTF-8, aka AL32UTF8) 3 Znak niekoniecznie są również 3 Bajty. Aby odczytać zawsze 3 bajty, musisz najpierw przekonwertować swój CLOB na BLOB.
  • Ten sam problem dotyczy BASE64_DECODE. Funkcja musi odczytać 4 bajty i przekształcić je na 3 bajty. Bajty te 3 niekoniecznie są również 3 Postacie
  • Zazwyczaj base64 String NEW_LINE (CR i/lub LF) postać co 64 znaków. Takie znaki nowej linii muszą być ignorowane podczas dekodowania.

Biorąc to wszystko pod uwagę pełne rozwiązanie funkcjonalny może być to jedno:

CREATE OR REPLACE FUNCTION DecodeBASE64(InBase64Char IN OUT NOCOPY CLOB) RETURN CLOB IS 

    blob_loc BLOB; 
    clob_trim CLOB; 
    res CLOB; 

    lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX; 
    dest_offset INTEGER := 1; 
    src_offset INTEGER := 1; 
    read_offset INTEGER := 1; 
    warning INTEGER; 
    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 UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(InBase64Char))); 
    END IF;   
    -- UTL_ENCODE.BASE64_DECODE is limited to 32k, process in chunks if bigger  

    -- Remove all NEW_LINE from base64 string 
    ClobLen := DBMS_LOB.GETLENGTH(InBase64Char); 
    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(blob_loc, 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(blob_loc, DBMS_LOB.GETLENGTH(buffer), buffer); 
     read_offset := read_offset + amount; 
    END LOOP; 

    DBMS_LOB.CREATETEMPORARY(res, TRUE); 
    DBMS_LOB.CONVERTTOCLOB(res, blob_loc, DBMS_LOB.LOBMAXSIZE, dest_offset, src_offset, DBMS_LOB.DEFAULT_CSID, lang_context, warning); 

    DBMS_LOB.FREETEMPORARY(blob_loc); 
    DBMS_LOB.FREETEMPORARY(clob_trim); 
    RETURN res;  

END DecodeBASE64; 




CREATE OR REPLACE FUNCTION EncodeBASE64(InClearChar IN OUT NOCOPY CLOB) RETURN CLOB IS 

    dest_lob BLOB; 
    lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX; 
    dest_offset INTEGER := 1; 
    src_offset INTEGER := 1; 
    read_offset INTEGER := 1; 
    warning INTEGER; 
    ClobLen INTEGER := DBMS_LOB.GETLENGTH(InClearChar); 

    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 InClearChar IS NULL OR NVL(ClobLen, 0) = 0 THEN 
     RETURN NULL; 
    ELSIF ClobLen <= 24000 THEN 
     RETURN UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(InClearChar))); 
    END IF; 
    -- UTL_ENCODE.BASE64_ENCODE is limited to 32k/(3/4), process in chunks if bigger  

    DBMS_LOB.CREATETEMPORARY(dest_lob, TRUE); 
    DBMS_LOB.CONVERTTOBLOB(dest_lob, InClearChar, DBMS_LOB.LOBMAXSIZE, dest_offset, src_offset, DBMS_LOB.DEFAULT_CSID, lang_context, warning); 
    LOOP 
     EXIT WHEN read_offset >= dest_offset; 
     DBMS_LOB.READ(dest_lob, amount, read_offset, buffer); 
     res := res || UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(buffer));  
     read_offset := read_offset + amount; 
    END LOOP; 
    DBMS_LOB.FREETEMPORARY(dest_lob); 
    RETURN res; 

END EncodeBASE64;