Vous avez changé l'appel à dbms_lob.substr()
et, ce faisant, vous avez supprimé le troisième argument, qui est le décalage. Comme vous ne spécifiez pas 1 par défaut, chaque fois que vous bouclez la boucle, vous obtenez la même valeur: les 2 000 premiers caractères de votre chaîne codée. Eh bien, vous obtiendrez 2000 pour beaucoup d'appels, puis une fois que n
sera assez grand, vous obtiendrez null, avec le code que vous avez posté. Puisque vous avez dit que l'état est «bloqué», cela suggère que ce que vous utilisez est légèrement différent.
Avec quelques légères modifications cela semble fonctionner:
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;
/
J'ai changé le CLOB manipulation légèrement; La concaténation est bonne mais c'est un peu plus explicite. Je ne suis pas sûr que je dérange avec la fonction imbriquée cependant, personnellement. Et je ne suis pas sûr que le calcul least()
ajoute vraiment quelque chose.
Mais cela peut erreur avec ORA-06502: PL/SQL: numeric or value error: invalid LOB locator specified: ORA-22275
ou ORA-14553: cannot perform a lob write operation inside a query
si la valeur codée en base64 est enroulée en ligne, ce qui est généralement le cas. Le premier morceau est décodé OK, mais le morceau suivant commence avec une nouvelle ligne non consommée qui jette tout et produit des ordures; finalement que la poubelle est nulle ou une autre valeur qui provoque l'une de ces exceptions.
Vous avez donc besoin de suivre la position lorsque vous vous déplacez dans le CLOB, en multiples de la longueur de la ligne; et ajuster la position suivie pour prendre des nouvelles lignes supplémentaires en compte:
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;
/
Ou dépouiller tous les caractères de retour newline/chariot potentiels premier:
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;
/
Cela fonctionne avec les valeurs de base64 emballés ou pas.
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
également testé avec des valeurs codées qui sont supérieures à la valeur substring_length
.
Je suppose que vous avez commencé [à partir de cette réponse] (http://stackoverflow.com/a/3806265/266304)? Que signifie «travailler partiellement»? Que se passe-t-il? Et quelle est la valeur décodée - devrait-elle être décodée en un CLOB ou un BLOB? –
@AlexPoole Oui, c'est vrai. il n'imprime qu'une ligne de valeur décodée et le développeur SQL passe à l'état bloqué. J'ai essayé de spouler le résultat dans un fichier, encore une fois il imprime seulement 1 ligne. Je ne sais pas ce qui me manque. Je suis en train de le décoder à un CLOB. – AKV