Friday, May 13, 2011

Oracle - Tracking Progress without DBMS_OUTPUT buffering issues

Oracle's dbms_output.put_line(...) functionality works fine unless you actually want to see output while a script is running.

Disclaimer: This "solution" requires access to V$SESSION. Confirm before preceeding.

For some reason known only to the Oracle gods [pun intended], this output is buffered until the block / script completes. My preferred workaround is to use DBMS_APPLICATION_INFO.SET_CLIENT_INFO(text) and then to query v$session for column CLIENT_INFO by the appropriate criteria (e.g. SID, Serial#, USERNAME,...).

select
   s.client_info,
   s.program, 
   s.status,
   s.SID||' - '||s.SERIAL#
from 
   v$session s
where
   s.username = 'JVOGEL';

Disclaimer: I'm sure there is a performance penalty of some sort. The real-time feedback is critical so I'm willing to accept the trade-off. In a loop you could choose to only invoke the routine every "x" number of occurrences.

I've encapsulated this into a "common" routine that I use called SetRunStatus.

/**
SetRunStatus('Evaluating Record Status',n_index => i,n_count => ln_count,n_id => lnt_remit_queue_id_list(i));
*/
PROCEDURE SetRunStatus(
 s_msg          IN   VARCHAR2,
 n_count        IN   NUMBER := Null,
 n_index        IN   NUMBER := Null,
 n_id           IN   NUMBER := Null )
IS
 ls_msg     VARCHAR2(64) := Null;

BEGIN
 
 IF (n_index > 0) THEN 
  ls_msg := ls_msg||' '||n_index;
 END IF;
 IF (n_count > 0) THEN
  ls_msg := ls_msg||' of '||n_count;
 END IF;
 IF (n_id > 0) THEN
  ls_msg := ls_msg||' [ID:'||n_id||']';
 END IF;
 ls_msg := SUBSTR('[Remit] '||TRIM(s_msg||ls_msg),1,64);

 DBMS_APPLICATION_INFO.SET_CLIENT_INFO(ls_msg);

 EXCEPTION
  WHEN OTHERS THEN 
   Null; -- Swallow any exceptions caused by SetRunStatus 

END SetRunStatus;

No comments: