2016-06-21 30 views
0

Ich habe die unten Sql Base64-Decoder von Stackoverflow (vergaß den Link). Ich habe mich leicht an meine Anforderungen angepasst. Wenn ich versuche, auszuführen, funktioniert die Decodierung nur teilweise. Ich habe maximal 10 MB im Wert von Base64 codiert Clob Daten pro Zeile in meiner DB.SQL dekodieren base64 in SQL-Entwickler

Nicht sicher, was ich vermisse.

create or replace FUNCTION Decode64_CLOB3(IN_CLOB CLOB) RETURN CLOB IS 
clobOriginal  clob; 
clobInBase64  clob; 
substring  varchar2(2000); 
n    pls_integer := 0; 
substring_length pls_integer := 2000; 

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 myCLobData into clobInBase64 from myClobTable where ID = 3; 
clobInBase64 :=IN_CLOB; 
    n := 0; 
    clobOriginal := null; 

while true loop 

substring := dbms_lob.substr(clobInBase64, 
          least(substring_length, length(clobInBase64) - (substring_length * n + 1))); 

    if substring is null then 
DBMS_OUTPUT.put_line('this is me 2'); 
    exit; 
end if; 
clobOriginal := clobOriginal || from_base64(substring); 
n := n + 1; 
    end loop; 
return clobOriginal; 
end; 

update2

habe ich einige Debugging und fand heraus, dass das Problem mit der Unter ist. Die Teilzeichenfolge funktioniert für die erste Schleife von (2000) char. aber es ist nicht in der Lage, den nächsten 2000 Char zu bewegen. Nicht sicher, was das Problem ist. Kann jemand beraten?

+0

Ich vermute, Sie haben [von dieser Antwort] gestartet (http://stackoverflow.com/a/3806265/266304)? Was bedeutet "teilweise arbeiten" - was passiert? Und was ist der dekodierte Wert - sollte es zu einem CLOB oder einem BLOB dekodieren? –

+0

@AlexPoole Ja, du hast Recht. Es druckt nur eine Zeile mit dekodiertem Wert, und der SQL-Entwickler geht in den Status "Ausgesetzt". Ich habe versucht, das Ergebnis in eine Datei zu spulen, wieder druckt es nur 1 Zeile. Nicht sicher, was ich vermisse. Ich dekodiere es zu einem CLOB. – AKV

Antwort

0

Sie haben den Aufruf in dbms_lob.substr() geändert und dabei das dritte Argument, nämlich den Offset, entfernt. Da Sie nicht angeben, dass der Standardwert 1 ist, erhalten Sie bei jedem Durchlauf der Schleife den gleichen Wert - die ersten 2000 Zeichen aus Ihrer codierten Zeichenfolge.

Nun, Sie erhalten 2000 für viele Anrufe, dann einmal n wird groß genug, erhalten Sie null, mit dem Code, den Sie gebucht haben. Da du gesagt hast, dass es in einen "aufgehängten" Zustand übergeht, was darauf hindeutet, dass du etwas läufst, ist das etwas anders.

Mit einigen leichten Modifikationen schien das funktionieren:

create or replace function decode64_clob3(p_clob_encoded clob) 
    return clob 
is 
    l_clob_decoded clob; 
    substring varchar2(2048); 
    substring_length pls_integer := 2048; 
    n pls_integer := 0; 

    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 
    dbms_lob.createtemporary(l_clob_decoded, false); 
    while true 
    loop 
    substring := dbms_lob.substr(p_clob_encoded, substring_length, 
     (substring_length * n) + 1); 
    if substring is null then 
     exit; 
    end if; 
    dbms_lob.append(l_clob_decoded, from_base64(substring)); 
    n := n + 1; 
    /* protective check for infinite loop while debugging 
    if n > 10000 then 
     dbms_output.put_line('n is ' || n); 
     exit; 
    end if; 
    */ 
    end loop; 

    return l_clob_decoded; 
end; 
/

ich die CLOB leicht Handhabung geändert; Verkettung ist in Ordnung, aber das ist ein wenig expliziter. Ich bin mir nicht sicher, ob ich mich persönlich mit der verschachtelten Funktion beschäftigen würde. Und ich bin mir nicht sicher, ob die Berechnung wirklich etwas hinzufügt.

Aber dies kann Fehler entweder ORA-06502: PL/SQL: numeric or value error: invalid LOB locator specified: ORA-22275 oder ORA-14553: cannot perform a lob write operation inside a query, wenn der Base64-codierte Wert Zeile umgebrochen ist, was normalerweise der Fall ist. Der erste Chunk wird korrekt decodiert, aber der nächste Chunk beginnt mit einem unverbrauchten Zeilenumbruch, der alles ausschaltet und Müll produziert; Schließlich ist dieser Müll null oder ein anderer Wert, der eine dieser Ausnahmen verursacht.

Sie müssen also die Position verfolgen, während Sie sich durch den CLOB in Vielfachen der Zeilenumbruchlänge bewegen; und stellen Sie die nachverfolgt Position zusätzliche Zeilenumbrüche zu berücksichtigen:

create or replace function decode64_clob3(p_clob_encoded clob) 
    return clob 
is 
    l_clob_decoded clob; 
    l_substring varchar2(2048); 
    l_substring_length pls_integer := 2048; 
    l_pos pls_integer := 1; 
begin 
    dbms_lob.createtemporary(l_clob_decoded, false); 
    while l_pos <= dbms_lob.getlength(p_clob_encoded) 
    loop 
    l_substring := dbms_lob.substr(p_clob_encoded, l_substring_length, l_pos); 
    if l_substring is null then 
     exit; 
    end if; 
    dbms_lob.append(l_clob_decoded, 
     utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(l_substring)))); 

    /* Adjust l_pos to skip over CR/LF chars if base64 is line-wrapped */ 
    l_pos := l_pos + length(l_substring); 
    while dbms_lob.substr(p_clob_encoded, 1, l_pos) in (chr(10), chr(13)) loop 
     l_pos := l_pos + 1; 
    end loop; 
    end loop; 

    return l_clob_decoded; 
end; 
/

Oder mögliche Newline/Carriage Return Zeichen ersten Streifen aus:

create or replace function decode64_clob3(p_clob_encoded clob) 
    return clob 
is 
    l_clob_encoded clob; 
    l_clob_decoded clob; 
    l_substring varchar2(2048); 
    l_substring_length pls_integer := 2048; 
    l_pos pls_integer := 1; 
begin 
    l_clob_encoded := replace(replace(p_clob_encoded, chr(10), null), chr(13), null); 
    dbms_lob.createtemporary(l_clob_decoded, false); 
    while l_pos <= dbms_lob.getlength(l_clob_encoded) 
    loop 
    l_substring := dbms_lob.substr(l_clob_encoded, l_substring_length, l_pos); 
    if l_substring is null then 
     exit; 
    end if; 
    dbms_lob.append(l_clob_decoded, 
     utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(l_substring)))); 
    l_pos := l_pos + length(l_substring); 
    end loop; 

    return l_clob_decoded; 
end; 
/

Dies funktioniert mit verpackten und unverpackten base64 Werte.

set serveroutput on 
with t (c) as (
    select utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw('Hello world'))) from dual 
) 
select c, decode64_clob3(c) 
from t; 

C 
-------------------------------------------------------------------------------- 
DECODE64_CLOB3(C) 
-------------------------------------------------------------------------------- 
SGVsbG8gd29ybGQ=                 
Hello world 

Auch mit codierten Werten getestet, die größer sind als der Wert substring_length.

+0

Danke für Ihr Update, aber die Ausführung der Funktion Ich bekomme diesen Fehler ** ORA-06502: PL/SQL: numerische oder Wert Fehler: ungültig LOB-Locator angegeben: ORA-22275 ORA-06512: bei "SYS.DBMS_LOB", Zeile 639 ** – AKV

+0

@AKV - initialisierst du immer noch den CLOB ('l_clob_decoded' in meiner Version) auf null oder benutzt du' dbms_lob.createtemporary'? –

+0

Ich habe versucht mit 'dbms_lob.createtemporary' auf ** true ** gesetzt. Auch versucht mit dem Setzen der Clob auf beide Möglichkeiten, ich bekomme den oben genannten Fehler. – AKV