procedimientos - ¿Hay alguna manera de descargar la salida de PL/SQL en Oracle?
procedimientos y funciones oracle pl/sql (5)
Dos alternativas:
Puede insertar sus detalles de registro en una tabla de registro mediante el uso de una transacción autónoma. Puede consultar esta tabla de registro en otra sesión de SQLPLUS / Toad / sql developer etc .... Debe utilizar una transacción autónoma para que sea posible confirmar su registro sin interferir en el manejo de la transacción en su script sql principal.
Otra alternativa es usar una función canalizada que devuelva su información de registro. Vea aquí para un ejemplo: http://berxblog.blogspot.com/2009/01/pipelined-function-vs-dbmsoutput.html Cuando usa una función pipeline no necesita usar otro desarrollador SQLPLUS / Toad / sql, etc. ... sesión.
Tengo un script SQL que se llama desde un script de shell y tarda mucho tiempo en ejecutarse. Actualmente contiene instrucciones dbms_output.put_line
en varios puntos. El resultado de estas instrucciones de impresión aparece en los archivos de registro, pero solo una vez que se ha completado.
¿Hay alguna forma de garantizar que el resultado aparezca en el archivo de registro a medida que se ejecuta el script?
Realmente no. La forma en que DBMS_OUTPUT funciona es la siguiente: tu bloque PL / SQL se ejecuta en el servidor de la base de datos sin interacción con el cliente. Entonces, cuando llamas a PUT_LINE, solo estás poniendo ese texto en un búfer en la memoria del servidor. Cuando se completa el bloque PL / SQL, se devuelve el control al cliente (supongo que SQLPlus en este caso); en ese punto, el cliente saca el texto del búfer llamando a GET_LINE y lo muestra.
Por lo tanto, la única forma en que puede hacer que la salida aparezca en el archivo de registro con más frecuencia es dividir un bloque grande de PL / SQL en varios bloques más pequeños, por lo que el control se devuelve al cliente con más frecuencia. Esto puede no ser práctico dependiendo de lo que esté haciendo su código.
Otras alternativas son usar UTL_FILE para escribir en un archivo de texto, que puede eliminarse cuando lo desee, o usar un procedimiento de transacción autónoma para insertar instrucciones de depuración en una tabla de base de datos y confirmar después de cada una.
Si es posible para usted, debe reemplazar las llamadas a dbms_output.put_line por su propia función.
Aquí está el código para esta función WRITE_LOG
- si desea tener la capacidad de elegir entre 2 soluciones de registro:
escribir registros en una tabla en una transacción autónoma
CREATE OR REPLACE PROCEDURE to_dbg_table(p_log varchar2)
-- table mode:
-- requires
-- CREATE TABLE dbg (u varchar2(200) --- username
-- , d timestamp --- date
-- , l varchar2(4000) --- log
-- );
AS
pragma autonomous_transaction;
BEGIN
insert into dbg(u, d, l) values (user, sysdate, p_log);
commit;
END to_dbg_table;
/
o escribe directamente en el servidor de BD que aloja tu base de datos
Esto usa el directorio de Oracle TMP_DIR
CREATE OR REPLACE PROCEDURE to_dbg_file(p_fname varchar2, p_log varchar2)
-- file mode:
-- requires
--- CREATE OR REPLACE DIRECTORY TMP_DIR as ''/directory/where/oracle/can/write/on/DB_server/'';
AS
l_file utl_file.file_type;
BEGIN
l_file := utl_file.fopen(''TMP_DIR'', p_fname, ''A'');
utl_file.put_line(l_file, p_log);
utl_file.fflush(l_file);
utl_file.fclose(l_file);
END to_dbg_file;
/
WRITE_LOG
Luego, el procedimiento WRITE_LOG
que puede cambiar entre los 2 usos, o puede desactivarse para evitar la pérdida de rendimiento ( g_DEBUG:=FALSE
).
CREATE OR REPLACE PROCEDURE write_log(p_log varchar2) AS
-- g_DEBUG can be set as a package variable defaulted to FALSE
-- then change it when debugging is required
g_DEBUG boolean := true;
-- the log file name can be set with several methods...
g_logfname varchar2(32767) := ''my_output.log'';
-- choose between 2 logging solutions:
-- file mode:
g_TYPE varchar2(7):= ''file'';
-- table mode:
--g_TYPE varchar2(7):= ''table'';
-----------------------------------------------------------------
BEGIN
if g_DEBUG then
if g_TYPE=''file'' then
to_dbg_file(g_logfname, p_log);
elsif g_TYPE=''table'' then
to_dbg_table(p_log);
end if;
end if;
END write_log;
/
Y aquí está cómo probar lo anterior:
1) Inicie esto ( modo de archivo ) desde su SQLPLUS:
BEGIN
write_log(''this is a test'');
for i in 1..100 loop
DBMS_LOCK.sleep(1);
write_log(''iter='' || i);
end loop;
write_log(''test complete'');
END;
/
2) en el servidor de la base de datos, abra un shell y
tail -f -n500 /directory/where/oracle/can/write/on/DB_server/my_output.log
Si tiene acceso al shell del sistema desde el entorno PL / SQL puede llamar a netcat:
BEGIN RUN_SHELL(''echo "''||p_msg||''" | nc ''||p_host||'' ''||p_port||'' -w 5''); END;
p_msg
- es un mensaje de registro v_host
es un host que ejecuta una secuencia de comandos python que lee datos del socket en el puerto v_port
.
aplogr este diseño cuando escribí aplogr para monitoreo de registros de shell y pl / sql en tiempo real.
el búfer de DBMS_OUTPUT
se lee cuando se llama al procedimiento DBMS_OUTPUT.get_line
. Si su aplicación cliente es SQL * Plus, significa que solo se enjuagará una vez que el procedimiento finalice.
Puede aplicar el método descrito en este SO para escribir el búfer DBMS_OUTPUT
en un archivo.