2009-09-21 1 views
40

мне нужно отлаживать в PL/SQL, чтобы понять раз процедур, я хочу использовать:Как перенаправить вывод DBMS_OUTPUT.PUT_LINE в файл?

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

, но я не понимаю, где выход идет на и как я могу перенаправить его в лог-файл, будут содержать все данные, которые я хочу собрать?

ответ

3

Использование UTL_FILE вместо DBMS_OUTPUT будет перенаправить вывод в файл:

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

+0

спасибо за быстрый ответ :) я попытаюсь дать этому попытку (но ему nds действительно сложно заставить его работать), вы знаете, как печатать DBMS_OUTPUT в файл (это может быть проще) –

12

Если вы только тестирование PL/SQL в SQL Plus вы можете направить его в файл, например так:

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 

IDE, такие как Toad и SQL Developer, могут захватывать выходные данные другими способами, но я не знаком с тем, как это сделать.

+0

спасибо, но я тестирую другое приложение, которое использует db pl/sql, и мне нужно информацию, которую нужно сохранить в файл, в то время как сценарий .sql не запускается из sqldeveloper, какие-либо идеи? –

+0

Ну, вы можете получить вывод, полученный DBMS_OUTPUT в вызывающем приложении, вызывая DBMS_OUTPUT.ENABLE перед записью любых сообщений, а затем вызывая DBMS_OUTPUT.GET_LINE или GET_LINES. Но для того, чтобы затем помещать эту информацию в файл, вам потребуется выполнить собственное открытие/запись/закрытие файла, например. используя UTL_FILE - в этом случае вы можете использовать UTL_FILE в первую очередь! –

3

В качестве примечания стороны, помните, что весь этот вывод создается на стороне сервера.

Использование DBMS_OUTPUT, текст генерируется на сервере, когда он выполняет ваш запрос и хранится в буфере. Затем он перенаправляется в клиентское приложение, когда сервер завершает поиск данных запроса. То есть вы получаете эту информацию только после завершения запроса.

С UTL_FILE вся зарегистрированная информация будет храниться в файле на сервере. Когда выполнение закончится, вам нужно будет перейти к этому файлу, чтобы получить информацию.

Надеюсь, это поможет.

35

DBMS_OUTPUT не самый лучший инструмент для отладки, поскольку большинство сред не используют его изначально. Если вы хотите захватить вывод DBMS_OUTPUT, вы должны просто использовать процедуру DBMS_OUTPUT.get_line.

Вот небольшой пример:

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

Как вы определяете переменные 'l_line VARCHAR2 (255); l_done NUMBER; l_file utl_file.file_type; '? –

+0

VARCHAR2, NUMBER являются [стандартными типами данных SQL] (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) является стандартным пакетом. –

29

В качестве альтернативы записи в файл, как о записи в таблице? Вместо вызова DBMS_OUTPUT.PUT_LINE вы могли бы назвать свою собственную процедуру DEBUG.OUTPUT что-то вроде:

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; 

Использование автономной транзакции позволяет сохранять отладочные сообщения, полученные от операций, которые получают откат (например, после того, как исключение составляет поднято), как это было бы, если бы вы использовали файл.

Булева переменная g_debugging - это переменная пакета, для которой по умолчанию используется значение false, и установлено значение true, когда требуется отладочный вывод.

Конечно, вам нужно управлять этим столом, чтобы он не рос вечно! Один из способов - это работа, выполняемая каждую ночь/неделю и удаление любых отладочных сообщений, которые являются «старыми».

+1

+1 для ответа на реальный базовый вопрос («как я могу войти в Oracle?») вместо вопроса о якобы. –

5

В дополнение к ответу Тони, если вы хотите узнать, где ваша программа PL/SQL тратит свое время, стоит также проверить часть документации Oracle PL/SQL на this.

+0

+1 для DBMS_PROFILER. Всегда лучше использовать встроенный Oracle, когда это возможно. – APC

+0

Да, это очень полезный совет. –

13

использование set serveroutput on;

, например:

set serveroutput on; 

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

Попробуйте:

SELECT systimestamp INTO time_db FROM dual ; 

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

Зачем нам это делать? –

-1

Старая нить, но есть другая альтернатива.

С 9i вы можете использовать функцию конвейерной таблицы.

Во-первых, создать тип в виде таблицы VARCHAR:

CREATE TYPE t_string_max IS TABLE OF VARCHAR2(32767); 

Во-вторых, обернуть свой код в конвейерном объявлении функции:

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

Заменить все DBMS_OUTPUT.PUT_LINE для PIPE ROW.

Наконец, назову его так:

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

Надеется, что это помогает.

1

Возможно записать файл непосредственно на сервер БД, на котором размещена ваша база данных, и это будет изменяться вместе с выполнением вашей программы PL/SQL.

Это использует Oracle directoryTMP_DIR; вы должны объявить его, и создать процедуру ниже:

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; 
/

Вот как его использовать:

1) Запустите это из вашего SQL * PLUS клиента:

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) на сервере базы данных, откройте оболочку и

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