Oracle
 sql >> Database >  >> RDS >> Oracle

ORA-22275:specificato localizzatore LOB non valido

Sì. Un LOB è un puntatore/riferimento a una memoria/disco. Devi prima "memalloc()" (... inizializzare) la memoria, assegnare il puntatore/riferimento alla tua variabile LOB. Ecco cosa dbms_lob.createTemporary() è per. A meno che tu non inizializzi una variabile LOB con un localizzatore LOB valido, tutte le tue operazioni su quella variabile LOB falliranno con ORA-22275: invalid LOB locator specified .

Miglioramento: Fai un po' di refactoring della tua funzione PL/SQL:(e tieni presente che ho usato una query fittizia per last_60_cpu_cursor cursore. Non riutilizzare il cursore, usa il tuo! :-))

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. Non è necessario aprire+prendere+chiudere il cursore. Un normale ciclo del cursore andrà benissimo (se non addirittura meglio, grazie all'implicito recupero di massa sotto i cofani).
  2. Dichiara esplicitamente la LOB temporanea come memorizzata nella cache (cache => true; come hai già fatto). Ciò garantisce che i blocchi di dati vengano aggiunti alla LOB in memoria, invece di essere aggiunti su disco (cache => false ).
  3. Concatena le stringhe da aggiungere al LOB in modo da ridurre al minimo il numero di chiamate al dbms_lob.append() .
  4. Rimuovi dbms_output.put_line() dalla tua funzione In caso di contenuti LOB maggiori di 32K, ciò genererebbe comunque un'eccezione.

Inoltre, dopo aver terminato di restituire il LOB al tuo ambiente Java, libera la LOB temporanea . (Non sono un tipo Java, non posso scrivere da solo lo snippet di codice Java.)

Inoltre, hai un errore concettuale nel tuo codice Java; registrando il ritorno della funzione come Types.VARCHAR è sbagliato. Dovresti invece utilizzare il tipo CLOB dedicato di Oracle . (Li ho visti in C#, anche Java deve averli.)

Inoltre, c'è un problema di prestazioni con la tua soluzione. La tua funzione restituisce un LOB. In PL/SQL, ogni valore di funzione viene restituito al chiamante come una copia completa del valore interno. Quindi, se si restituisce un LOB da una funzione, il contenuto LOB viene duplicato in background con un nuovo localizzatore LOB(/pointer/reference). Dovresti usare Potresti considerare di utilizzare una procedura memorizzata invece di una funzione e passare la LOB a Java come out nocopy parametro. Il processo memorizzato sarebbe quindi simile a questo:

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;

L'aspetto della tua chiamata Java dipende da te e da Documento JDBC ; ma, di sicuro, una LOB restituita in questo modo significherebbe nessuna copia del contenuto in background. Naturalmente resta valida la necessità di liberare la LOB temporanea allocata.