Comment rediriger la sortie de sortie DBMS.METTRE la LIGNE dans un fichier?

j'ai besoin de déboguer en pl / sql pour calculer les temps des procédures, je veux utiliser:

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

mais je ne comprends pas d'où la sortie passe et comment puis-je rediriger vers un fichier journal qui contiendra toutes les données que je veux recueillir?

44
demandé sur MatthewMartin 2009-09-21 13:07:23

10 réponses

DBMS_OUTPUT n'est pas le meilleur outil pour déboguer, car la plupart des environnements ne l'utilisent pas nativement. Si vous voulez capturer la sortie de DBMS_OUTPUT cependant, vous utiliserez simplement la procédure DBMS_OUTPUT.get_line .

Voici un petit exemple:

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
35
répondu Vincent Malgrat 2009-09-21 10:05:18

comme alternative à l'écriture d'un fichier, que diriez-vous d'écrire à une table? Au lieu d'appeler DBMS_OUTPUT.PUT_LINE vous pouvez appeler votre propre débogueur.Procédure de sortie quelque chose comme:

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'utilisation d'une transaction autonome vous permet de conserver les messages de débogage produits à partir de transactions qui sont retournées (par exemple après qu'une exception a été soulevée), comme cela se produirait si vous utilisiez un fichier.

la variable booléenne g_debugging est une variable de paquet qui peut être définie par défaut à false et à true lorsque la sortie de débogage est requise.

bien sûr, vous devez gérer cette table pour qu'elle ne pousse pas pour toujours! Une façon serait un travail qui court chaque nuit / hebdomadaire et supprime tous les messages de débogage qui sont"vieux".

29
répondu Tony Andrews 2009-09-21 10:34:46

utilisation set serveroutput;

par exemple:

set serveroutput on;

DECLARE
x NUMBER;
BEGIN
x := 72600;
dbms_output.put_line('The variable X = '); dbms_output.put_line(x);
END;
14
répondu Mahmoud Hanafy 2013-04-16 05:46:27

si vous ne faites que tester votre PL/SQL en SQL Plus, vous pouvez le diriger vers un fichier comme celui-ci:

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

IDEs comme Toad et SQL Developer peut capturer la sortie d'une autre manière, mais je ne sais pas comment.

12
répondu Tony Andrews 2015-06-03 22:37:29

en plus de la réponse de Tony, si vous cherchez à savoir où votre programme PL/SQL passe son temps, il est également intéressant de vérifier cette partie de la documentation Oracle PL/SQL.

5
répondu Ian Carpenter 2009-09-21 10:41:35

en utilisant UTL_FILE au lieu de DBMS_OUTPUT redirigera la sortie vers un fichier:

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

3
répondu Rafa de Castro 2009-09-21 09:11:50

comme note, rappelez-vous que toute cette sortie est générée du côté du serveur.

en utilisant DBMS_OUTPUT, le texte est généré dans le serveur pendant qu'il exécute votre requête et stocké dans un tampon. Il est ensuite redirigé vers votre application client lorsque le serveur termine la récupération de données de requête. C'est-à-dire que vous n'obtenez cette information que lorsque la requête se termine.

avec UTL_FILE toutes les informations enregistrées seront stockées dans un fichier dans le serveur. Lorsque l' se termine, vous aurez pour accéder à ce fichier pour obtenir les informations.

Espérons que cette aide.

3
répondu Juan Calero 2009-09-21 09:50:04

il est possible d'écrire un fichier directement sur le serveur DB qui héberge votre base de données, et cela changera avec l'exécution de votre programme PL/SQL.

utilise le Oracle directory TMP_DIR ; vous devez le déclarer, et créer la procédure suivante:

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

, Voici comment l'utiliser:

1) Lancez ceci à partir de votre SQL * Plus client:

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) sur le serveur de base de données, ouvrez un shell et

    tail -f -n500 /directory/where/oracle/can/write/on/DB_server/my_output.log
1
répondu J. Chomel 2016-09-23 14:09:55

un vieux fil, mais il y a une autre alternative.

depuis 9i vous pouvez utiliser la fonction de table pipelined.

tout d'abord, créer un type comme une table de varchar:

CREATE TYPE t_string_max IS TABLE OF VARCHAR2(32767);

deuxièmement, enveloppez votre code dans une déclaration de fonction pipelinée:

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

remplacer DBMS_OUTPUT.PUT_LINE par PIPE ROW .

enfin, appelez ça comme ça:

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

Hope il aide.

-1
répondu Felypp Oliveira 2016-07-20 14:29:01

Essayez Ceci:

SELECT systimestamp INTO time_db FROM dual ;

DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);
-4
répondu Mark 2016-08-23 18:04:24