2009-09-21 22 views
40

Ho bisogno di eseguire il debug di PL/SQL di capire i tempi delle procedure, voglio usare:Come reindirizzare l'output di DBMS_OUTPUT.PUT_LINE in un file?

SELECT systimestamp FROM dual INTO time_db; 
DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db); 

ma non capisco dove l'uscita va a e come posso reindirizzare a un file di registro conterrà tutti i dati che voglio raccogliere?

risposta

3

Utilizzando UTL_FILE invece di DBMS_OUTPUT reindirizza output in un file:

http://oreilly.com/catalog/oraclebip/chapter/ch06.html

+0

grazie per la rapida risposta :) cercherò di dare una prova (ma sou nds davvero difficile farlo funzionare), hai qualche idea su come stampare DBMS_OUTPUT su un file (potrebbe essere più facile) –

12

Se sono solo test del PL/SQL in SQL Inoltre è possibile indirizzare in un file in questo modo:

spool output.txt 
set serveroutput on 

begin 
    SELECT systimestamp FROM dual INTO time_db; 
    DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db); 
end; 
/

spool off 

Gli IDE come Toad e SQL Developer possono acquisire l'output in altri modi, ma non ho familiarità con come.

+0

grazie, ma sto testando un'applicazione diversa che usa il db pl/sql e ho bisogno le informazioni da salvare in un file mentre lo script .sql non viene eseguito da sqldeveloper, qualche idea? –

+0

Bene, è possibile ottenere l'output prodotto da DBMS_OUTPUT nell'applicazione chiamante chiamando DBMS_OUTPUT.ENABLE prima di scrivere qualsiasi messaggio, quindi chiamare DBMS_OUTPUT.GET_LINE o GET_LINES. Ma per poi inserire tali informazioni in un file richiederebbe la propria apertura/scrittura/chiusura di file, ad es. usando UTL_FILE - nel qual caso potresti usare UTL_FILE in primo luogo! –

3

Come nota a margine, ricordare che tutto questo output è generato sul lato server.

Utilizzando DBMS_OUTPUT, il testo viene generato nel server mentre esegue la query e memorizzato in un buffer. Viene quindi reindirizzato all'app client quando il server termina il recupero dei dati della query. Cioè, ottieni queste informazioni solo al termine della query.

Con UTL_FILE tutte le informazioni registrate verranno memorizzate in un file nel server. Al termine dell'esecuzione dovrai navigare verso questo file per ottenere le informazioni.

Spero che questo aiuti.

35

DBMS_OUTPUT non è lo strumento migliore per eseguire il debug, poiché la maggior parte degli ambienti non lo utilizza in modo nativo. Tuttavia, se si desidera acquisire l'output di DBMS_OUTPUT, utilizzare semplicemente la procedura DBMS_OUTPUT.get_line.

Ecco un piccolo esempio:

SQL> create directory tmp as '/tmp/'; 

Directory created 

SQL> CREATE OR REPLACE PROCEDURE write_log AS 
    2  l_line VARCHAR2(255); 
    3  l_done NUMBER; 
    4  l_file utl_file.file_type; 
    5 BEGIN 
    6  l_file := utl_file.fopen('TMP', 'foo.log', 'A'); 
    7  LOOP 
    8  EXIT WHEN l_done = 1; 
    9  dbms_output.get_line(l_line, l_done); 
10  utl_file.put_line(l_file, l_line); 
11  END LOOP; 
12  utl_file.fflush(l_file); 
13  utl_file.fclose(l_file); 
14 END write_log; 
15/

Procedure created 

SQL> BEGIN 
    2  dbms_output.enable(100000); 
    3  -- write something to DBMS_OUTPUT 
    4  dbms_output.put_line('this is a test'); 
    5  -- write the content of the buffer to a file 
    6  write_log; 
    7 END; 
    8/

PL/SQL procedure successfully completed 

SQL> host cat /tmp/foo.log 

this is a test 
+0

Come si definiscono le variabili 'l_line VARCHAR2 (255); l_done NUMBER; l_file utl_file.file_type; '? –

+0

VARCHAR2, NUMBER sono [tipi di dati SQL standard] (http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/datatypes.htm#CHDHAEGF). ['UTL_FILE'] (http://docs.oracle.com/cd/E11882_01/appdev.112/e25788/u_file.htm#BABGGEDF) è un pacchetto standard. –

29

Come alternativa alla scrittura in un file, che ne dite di scrivere a un tavolo? Invece di chiamare DBMS_OUTPUT.PUT_LINE si potrebbe chiamare la propria procedura DEBUG.OUTPUT qualcosa di simile:

procedure output (p_text varchar2) is 
    pragma autonomous_transaction; 
begin 
    if g_debugging then 
     insert into debug_messages (username, datetime, text) 
     values (user, sysdate, p_text); 
     commit; 
    end if; 
end; 

L'uso di una transazione autonoma consente di conservare i messaggi di debug prodotte da operazioni che vengono rollback (ad esempio dopo un'eccezione è sollevato), come accadrebbe se si stesse utilizzando un file.

La variabile booleana g_debugging è una variabile del pacchetto che può essere impostata su false e impostata su true quando è richiesto l'output di debug.

Ovviamente, è necessario gestire quel tavolo in modo che non cresca per sempre! Un modo sarebbe un lavoro che viene eseguito ogni notte/settimanalmente e cancella tutti i messaggi di debug che sono "vecchi".

+1

+1 per rispondere alla domanda reale sottostante ("come posso accedere da Oracle?") invece della domanda apparente –

5

Oltre alla risposta di Tony, se stai cercando di scoprire dove il tuo programma PL/SQL sta spendendo il suo tempo, vale anche la pena di controllare la parte this della documentazione Oracle PL/SQL.

+0

+1 per DBMS_PROFILER È sempre preferibile utilizzare un built-in Oracle quando possibile – APC

+0

Sì, questo è un suggerimento molto utile –

13

use set servoutput on;

ad esempio:

set serveroutput on; 

DECLARE 
x NUMBER; 
BEGIN 
x := 72600; 
dbms_output.put_line('The variable X = '); dbms_output.put_line(x); 
END; 
-4

Prova questo:

SELECT systimestamp INTO time_db FROM dual ; 

DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db); 
+0

Perché dovremmo provare comunque? –

-1

Un filo vecchio, ma c'è un'altra alternativa.

Poiché 9i è possibile utilizzare la funzione tabella pipeline.

In primo luogo, creare un tipo come una tabella di varchar:

CREATE TYPE t_string_max IS TABLE OF VARCHAR2(32767); 

In secondo luogo, avvolgere il codice in una dichiarazione di funzione pipeline:

CREATE FUNCTION fn_foo (bar VARCHAR2) -- your params 
    RETURN t_string_max PIPELINED IS 
    -- your vars 
BEGIN 
    -- your code 
END; 
/

Sostituire tutti DBMS_OUTPUT.PUT_LINE per PIPE ROW.

Infine, chiamare in questo modo:

SELECT * FROM TABLE(fn_foo('param')); 

Speranza che aiuta.

1

È possibile scrivere un file direttamente sul server DB che ospita il database e che cambierà insieme all'esecuzione del programma PL/SQL.

Questo utilizza la Oracle directoryTMP_DIR; si deve dichiarare, e creare la seguente procedura:

CREATE OR REPLACE PROCEDURE write_log(p_log varchar2) 
    -- file mode; thisrequires 
--- 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', 'my_output.log', 'A'); 
    utl_file.put_line(l_file, p_log); 
    utl_file.fflush(l_file); 
    utl_file.fclose(l_file); 
END write_log; 
/

Ecco come usarlo:

1) lanciare questo da SQL * Plus cliente:

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) sul server di database, aprire una shell e

 
    tail -f -n500 /directory/where/oracle/can/write/on/DB_server/my_output.log