2016-06-21 1 views
0

J'ai eu le décodeur base64 sql inférieur de stackoverflow (j'ai oublié le lien). J'ai légèrement modifié à mon exigence. Lorsque j'essaie d'exécuter, le décodage ne fonctionne que partiellement. J'ai un maximum de 10 Mo de base64 codé données clob par ligne dans ma base de données.SQL décode base64 dans le développeur sql

Je ne sais pas ce qui me manque.

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

J'ai fait quelques débogage et trouvé que le problème est dû à la sous-chaîne. La sous-chaîne fonctionne correctement pour le premier tour de (2000) char. mais ce n'est pas en mesure de déplacer le prochain 2000 char. Je ne sais pas quel est le problème. Quelqu'un peut-il conseiller.

+0

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

+0

@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

Répondre

0

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.

+0

Merci pour votre mise à jour, cependant l'exécution de la fonction J'obtiens cette erreurr ** ORA-06502: PL/SQL: erreur numérique ou de valeur: invalide localisateur LOB spécifié: ORA-22275 ORA-06512: à "SYS.DBMS_LOB", line 639 ** – AKV

+0

@AKV - êtes-vous encore en train d'initialiser le CLOB ('l_clob_decoded' dans ma version) à null, ou utilisez-vous' dbms_lob.createtemporary'? –

+0

Je suis essayé avec 'dbms_lob.createtemporary' réglé sur ** true **. Également essayé avec la définition du clob à zéro dans les deux sens, je reçois l'erreur mentionnée ci-dessus. – AKV