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
.
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? –
@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