sql >> Base de Datos >  >> RDS >> Oracle

ORA-22275:se especificó un localizador de LOB no válido

Sí. Un LOB es un puntero/referencia a una memoria/almacenamiento en disco. Primero debe "memalloc ()" (... inicializar) el almacenamiento, asignar el puntero/referencia a su variable LOB. Eso es lo que dbms_lob.createTemporary() es para. A menos que inicialice una variable LOB con un localizador LOB válido, todas sus operaciones en esa variable LOB fallarán con ORA-22275: invalid LOB locator specified .

Mejora: Haga que su función PL/SQL se refactorice un poco:(Y tenga en cuenta que utilicé una consulta ficticia para el last_60_cpu_cursor cursor. ¡No reutilices el cursor, utiliza el tuyo propio! :-))

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. No es necesario abrir, buscar y cerrar el cursor. Un bucle de cursor regular funcionará bien (si no incluso mejor, gracias a la búsqueda masiva implícita).
  2. Declare explícitamente el LOB temporal como almacenado en caché (cache => true; como ya tienes). Esto garantiza que los fragmentos de datos se agreguen al LOB en la memoria, en lugar de agregarse al disco (cache => false ).
  3. Concatene las cadenas que se agregarán al LOB para minimizar el número de llamadas al dbms_lob.append() .
  4. Elimine dbms_output.put_line() de su función. En el caso de contenidos de LOB superiores a 32K, esto arrojaría una excepción de todos modos.

Además, una vez que haya terminado de devolver el LOB a su entorno Java, liberar el LOB temporal . (No soy un tipo de Java, no puedo escribir el fragmento de código de Java yo mismo).

Además, tiene un error conceptual en su código Java; registrando el retorno de la función como Types.VARCHAR Está Mal. Debería usar el tipo CLOB dedicado de Oracle . (Los he visto en C#, Java también debe tenerlos).

Además, hay un problema de rendimiento con su solución. Su función devuelve un LOB. En PL/SQL, cada valor de función se devuelve a quien lo llama como una copia profunda del valor interno. Por lo tanto, si devuelve un LOB desde una función, el contenido de LOB se duplica en segundo plano con un nuevo localizador de LOB (/puntero/referencia). Deberías usar Puede considerar usar un procedimiento almacenado en lugar de una función y pasar el LOB a Java como out nocopy parámetro. El proceso almacenado se vería así:

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;

El aspecto de su llamada Java depende de usted y de Documento JDBC ; pero, sin duda, un LOB devuelto de esta manera significaría que no se copiaría el contenido de fondo. Por supuesto, aún se aplica la necesidad de liberar el LOB temporal asignado.