Oracle
 sql >> Base de données >  >> RDS >> Oracle

ORA-22275 : localisateur LOB non valide spécifié

Oui. Un LOB est un pointeur/référence vers une mémoire/un stockage sur disque. Vous devez d'abord "memalloc()" (... initialiser) le stockage, affecter le pointeur/référence à votre variable LOB. C'est ce que dbms_lob.createTemporary() est pour. Sauf si vous initialisez une variable LOB avec un localisateur LOB valide, toutes vos opérations sur cette variable LOB échoueront avec ORA-22275: invalid LOB locator specified .

Amélioration : Faites refactoriser un peu votre fonction PL/SQL :(Et veuillez noter que j'ai utilisé une requête factice pour le last_60_cpu_cursor le curseur. Ne réutilisez pas le curseur, utilisez le vôtre ! :-))

create or replace
function statistics_function
    ( namein                        in varchar2 )
    return clob
is
    line                            clob;
    cursor last_60_cpu_cursor       is
        select 1 as last_60_cpu, sysdate as last_60_event_date
        from dual
    ;
begin
    dbms_lob.createtemporary(lob_loc => line, cache => true, dur => dbms_lob.call);

    for cv in last_60_cpu_cursor loop
        dbms_lob.append(line, to_char(cv.last_60_event_date)||'i'||to_char(cv.last_60_cpu)||chr(10));
    end loop;

    dbms_lob.append(line, 'last_60_cpu'||chr(10));

    return line;
end statistics_function;
  1. Vous n'avez pas besoin d'ouvrir+récupérer+fermer le curseur. Une boucle de curseur régulière fera très bien l'affaire (sinon encore mieux, grâce à la récupération implicite en bloc sous les capots).
  2. Déclarer explicitement le LOB temporaire comme mis en cache (cache => true; comme vous l'avez déjà). Cela garantit que les blocs de données sont ajoutés au LOB en mémoire, au lieu d'être ajoutés sur le disque (cache => false ).
  3. Concaténer les chaînes à ajouter au LOB afin de minimiser le nombre d'appels au dbms_lob.append() .
  4. Supprimez le dbms_output.put_line() de votre fonction. Dans le cas d'un contenu LOB supérieur à 32 Ko, cela lèverait de toute façon une exception.

De plus, une fois que vous avez terminé de renvoyer le LOB à votre environnement Java, libérez le LOB temporaire . (Je ne suis pas un gars Java, je ne peux pas écrire l'extrait de code Java moi-même.)

De plus, vous avez une erreur conceptuelle dans votre code Java ; enregistrer le retour de la fonction en tant que Types.VARCHAR est faux. Vous devriez plutôt utiliser le le type CLOB dédié d'Oracle . (J'en ai vu en C#, Java doit en avoir aussi.)

En outre, il existe un problème de performances avec votre solution. Votre fonction renvoie un LOB. En PL/SQL, chaque valeur de fonction est renvoyée à son appelant sous la forme d'une copie complète de la valeur interne. Par conséquent, si vous renvoyez un LOB à partir d'une fonction, le contenu du LOB est dupliqué en arrière-plan avec un nouveau localisateur de LOB (/pointeur/référence). Vous devez utiliser Vous pouvez envisager d'utiliser une procédure stockée au lieu d'une fonction et transmettre le LOB à Java en tant que out nocopy paramètre. La procédure stockée ressemblerait alors à ceci :

create or replace
procedure statistics_function
    ( namein                        in varchar2
    , lob_out                       out nocopy clob )
is
    cursor last_60_cpu_cursor       is
        select 1 as last_60_cpu, sysdate as last_60_event_date
        from dual
    ;
begin
    dbms_lob.createtemporary(lob_loc => lob_out, cache => true, dur => dbms_lob.session);

    for cv in last_60_cpu_cursor loop
        dbms_lob.append(lob_out, to_char(cv.last_60_event_date)||'i'||to_char(cv.last_60_cpu)||chr(10));
    end loop;

    dbms_lob.append(lob_out, 'last_60_cpu'||chr(10)||chr(10));
end statistics_function;

À quoi ressemblerait votre appel Java, cela dépend de vous et de Documentation JDBC ; mais, à coup sûr, un LOB renvoyé de cette manière signifierait qu'il n'y aurait pas de copie du contenu en arrière-plan. Bien sûr, la nécessité de libérer le LOB temporaire alloué s'applique toujours.