views:

2069

answers:

9

I have a number of pl/sql procedures that can take several minutes to run. While developing them, I've added a few print statements to help debug and also provide some feedback and progress indicators. Initially, I ran these on small test sets and output was almost instantaneous. Now that I'm testing with larger test sets that take several minutes to run, I find that printing to the console is no longer suitable, because nothing gets printed until the procedure ends. I'm used to working in environments that do not buffer their output and print it immediately and adding simple print-statements for simple debugging and diagnostic is common.

Is it possible in pl/sql to print output immediately (not buffered)? If not, what alternatives do people recommend to get a similar result?

+7  A: 

we have a small trick for this.

you can use DBMS_APPLICATION_INFO.set_client_info(" some information here"); creating some variables and replace the string inside " ".

and use select client_info from v$session to monitor the progress.

Henry Gao
I have access to a v$session_longops and v$session_connect_info and neither of them has a client_info field. Would v$session_longops be just as good?
FrustratedWithFormsDesigner
no, you need to use v$session view. ask you DBA if you do not have access.
Henry Gao
+1  A: 

There are generally two options:

  • Send the output to an Oracle table (or temporary table)
  • Write to the (database host) filesystem with UTL_FILE

If you don't have OS access to the database host, you can still write to the dbhost filesystem and bind an Oracle externally-defined table to the file so it can be queried with a SELECT.

dpbradley
+8  A: 

You can have a procedure that writes messages to a table using an autonomous transaction something like:

procedure log (p_message)
is
    pragma autonomous_transaction;
begin
    insert into message_log (user, datetime, message)
    values (user, sysdate, p_message);
    commit;
end;

Then monitor the table from another Oracle session.

Tony Andrews
More information on pragma autonomous_transaction http://stackoverflow.com/questions/1335331/autonomoustransaction
caddis
This looks good, I'll probably be trying it out today :)How does it compare to the other suggestion of using pipes? Which will be easier to view and monitor?
FrustratedWithFormsDesigner
I haven't used the pipe method, so can't comment on that. One difference with the table method is that the messages are persistent. This can be an advantage, but it also means you have to manage them so that the table doesn't grow infinitely!
Tony Andrews
I'm going to accept this answer as persistence could be a serious issue (in the sense that we will need it!) further down the road, but the pipes idea and even the pipelined function idea were interesting. If I get some downtime, I will have to try them all!
FrustratedWithFormsDesigner
A: 

It may depend on your client tool. I haven't used SQL*Plus in a while, but when I'm debugging procedures in PL/SQL Developer, I open a command window and issue a SET SERVEROUTPUT ON command. Then when I execute the procedure, anything printed by DBMS_OUTPUT.PUT_LINE shows up right away.

Edit: you're right, I guess I was only seeing that with larger amounts of output or something. Anyhow I did some searching online and came across this log4plsql - may be useful.

Dan
I am usign PL/SQL Developer, that does not work. All of the output is printed at once when the script has finished executing.
FrustratedWithFormsDesigner
+1  A: 

An alternative is to use a pipelined function that returns your logging information. See here for an example: http://berxblog.blogspot.com/2009/01/pipelined-function-vs-dbmsoutput.html When you use a pipelined function you don't have to use another SQLPLUS/Toad/sql developer etc... session.

tuinstoel
This is interesting, but wouldn't I have to modify my existing function to be pipelined, or possibly wrap it in a pipeline function?
FrustratedWithFormsDesigner
Of course you have to change your code. Just wrapping it inside a pipelined function doesn't help you because you want immediate logging and not only logging when something is done.
tuinstoel
A: 

See the answer i gave to this SO question

Paul James
+1  A: 

I've been using dbms_pipe for this purpose. Send messages to a named pipe and read them from another session. This method may not work in a RAC environment when the writing and reading processes may connect to a different node.

Alternatively you can insert messages into a table using a procedure that runs in its own session using "pragma autonomous_transaction". You can the query these messages from another session

Edit: I see that my second option has already been mentioned.

Rene
Both of these look like interesting possibilities, although I get an error (probably permissions-related) when I try to use teh dbms_pipe package.What are the pros and cons of each approach? I don't know much about Oracle pipes so I'm not sure how to evaluate that, but it looks closer to what I want than a table-driven solution.
FrustratedWithFormsDesigner
+1  A: 

You can use DBMS Pipe and the Pipe Viewer in PL/SQL Developer to asynchronously catch all infos as they are put into the pipe.

Be careful to only put things into a pipe when there's someone to read it. Otherwise, your call will fail when the pipe is full.

There's also the possibility of using events, PL/SQL Developer has an event monitor as well. And the docs should provide an example of how to do it.

Robert Giesecke
This looks good, but I get an error: "identifier 'DBMS_PIPE' must be declared", I think I need to talk to the DBA about this. Probably a permissions issue.
FrustratedWithFormsDesigner
A: 

Another option is to have your PL/SQL call a procedure to send an email with the log message in it. This requires that your database has email sending capability, which can be added using UTL_SMTP.

Leigh Riffel