Skip to Main Content
  • Questions
  • Locate Previous SQL statement executed

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Nikos.

Asked: November 09, 2001 - 11:27 am UTC

Last updated: December 01, 2011 - 7:12 am UTC

Version: 8.1.5

Viewed 10K+ times! This question is

You Asked

Hello Tom,
I'd like to know if there is a way to locate the previous to the last SQL statement executed by a session (because the last one will be the one at V$SESSION, V$SQLTEXT to find out the statement) FROM WITHIN THE SAME SESSION. I need this info, so when an error is encountered (at the EXCEPTION section of a PL/SQL procedure), I'll be able to locate the problematic statement in a straightforward manner and log it.
e.g.
Procedure test
insert into t1(a, b, c) values (1, 2, 3);
update t1 set a = a + 1;
EXCEPTION
WHEN OTHERS THEN
*** Can I find here the problematic statement without
*** the use of variables before each statement?

I'm not sure this is possible though, because that would require a statement log per session (pretty much data). Anyway, I'd like your confirmation, before I move on to alternative solutions.
Thank you and keep the good work

and Tom said...

Ok, here is one way to do it. Actually, I'll have to show you an 815 way and then a better 816 and up way.... (maybe enough to motivate you to upgrade!)

Anyway, in 815 we added a DBMS_TRACE package. If you enable exception tracing we can

o capture the exception details into a trace file in 815
o capture the exception details into a TABLE in 816 and up.


In 815, it would look like this:

ops$tkyte@ORA815.US.ORACLE.COM> create table t
2 ( x int constraint check_x check (x>0),
3 y int constraint check_y check (y>0)
4 );

Table created.

ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM> create or replace directory udump_dir
2 as '/export/home2/ora815/admin/ora815/udump'
3 /

Directory created.

ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM> create or replace procedure p( p_x in int, p_y in int )
2 as
3 begin
4 insert into t values ( p_x, p_y );
5 update t set y = -p_y where x = p_x;
6 exception
7 when others then
8 declare
9 l_bfile bfile;
10 l_file varchar2(255);
11 l_str varchar2(255);
12 begin
13
14 select c.value || '/' || instance || '_ora_' ||
15 ltrim(to_char(to_number(a.spid),'fm99999')) || '.trc'
16 into l_file
17 from v$process a, v$session b, v$parameter c, v$thread c
18 where a.addr = b.paddr
19 and b.audsid = userenv('sessionid')
20 and c.name = 'user_dump_dest';
21
22 l_bfile := bfilename( 'UDUMP_DIR', l_file );
23 dbms_lob.fileopen( l_bfile );
24
25 l_str := utl_raw.cast_to_varchar2(
26 dbms_lob.substr( l_bfile, 250,
greatest(1,dbms_lob.getlength(l_bfile)-250) )
27 );
28 dbms_output.put_line( l_str );
29 end;
30 end;
31 /

Procedure created.

ops$tkyte@ORA815.US.ORACLE.COM>
ops$tkyte@ORA815.US.ORACLE.COM> exec dbms_trace.set_plsql_trace( dbms_trace.trace_all_exceptions );

PL/SQL procedure successfully completed.

ops$tkyte@ORA815.US.ORACLE.COM> exec p(1,1)
D:(9.474) 2001.11.12.14.37.17.000
------------ PL/SQL TRACE INFORMATION -----------
Levels set : 4
------------ PL/SQL TRACE
INFORMATION -----------
Levels set : 4
Trace: Pre-defined exception - OER 2290 at line 5 of PROCEDURE OPS$TKYTE.P:

PL/SQL procedure successfully completed.

ops$tkyte@ORA815.US.ORACLE.COM> exec p(-1,-1)
line 5 of PROCEDURE OPS$TKYTE.P:
------------ PL/SQL TRACE INFORMATION -----------
Levels set : 4
------------ PL/SQL TRACE
INFORMATION -----------
Levels set : 4
Trace: Pre-defined exception - OER 2290 at line 4 of PROCEDURE OPS$TKYTE.P:

PL/SQL procedure successfully completed


Here, we have a procedure that will always fail either on the INSERT or the UPDATE. We run it two times -- failing on each. The trace information we collected shows use the line number and procedure that failed.

I would expect you would put the code in the exception block in a STORED PROCEDURE of course, you wouldn't what that code embedded everywhere of course.

Another reason for putting it in a stored procedure is that in 816, you'll change the interface. The data is stored in a TABLE instead of a trace file (much nicer, easier to get the info). In 816 and up, this example would be:


ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace procedure p( p_x in int, p_y in int )
2 as
3 begin
4 insert into t values ( p_x, p_y );
5 update t set y = -p_y where x = p_x;
6 exception
7 when others then
8 declare
9 l_runid number;
10 begin
11 select sys.plsql_trace_runnumber.currval into l_runid
12 from dual;
13
14 for x in ( select *
15 from sys.plsql_trace_events
16 where runid = l_runid
17 and event_kind = 52
18 order by event_seq DESC )
19 loop
20 dbms_output.put_line( 'Exception occured in source ' || x.event_unit ||
21 ' on line ' || x.event_line );
22 exit;
23 end loop;
24 end;
25 end;
26 /

Procedure created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_trace.set_plsql_trace( dbms_trace.trace_all_exceptions );

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec p(1,1)
Exception occured in source P on line 5

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec p(-1,-1)
Exception occured in source P on line 4

PL/SQL procedure successfully completed.



Rating

  (45 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

How about MTS mode?

Nikos Papakyriakou, November 13, 2001 - 3:24 am UTC

Tom thanks a lot for your reply. It was much help. One more thing though. Oracle manual (8.1.5) notes that Trace cannot be used when in MTS mode. Is there an alternative when running in this mode?

Tom Kyte
November 13, 2001 - 8:30 am UTC

That is because your trace file is not your trace file (and this only applies in 815 -- maybe a better reason still to upgrade to supported software).

In 816 and up, since it writes to a table, your trace is your trace -- we can id it via the sequence -- there is no ambiguity.

When using MTS in 815, you will not be able to use this technique and there is no alternative short of coding it yourself.  You could use a procedure like my "who_called_me" 
http://asktom.oracle.com/~tkyte/who_called_me/index.html

and you would be able to write a small routine "mark" or something like that that asked "who called me" and gets the line number, owner, procedure name it its caller and saves them in a set of package variables.  You could then code:

ops$tkyte@ORA815.US.ORACLE.COM> create or replace package mark
  2  as
  3      g_owner    varchar2(30);
  4      g_name     varchar2(30);
  5      g_lineno   number;
  6      g_caller_t varchar2(255);
  7  
  8      procedure it;
  9  end;
 10  /

Package created.

ops$tkyte@ORA815.US.ORACLE.COM> 
ops$tkyte@ORA815.US.ORACLE.COM> create or replace package body mark
  2  as
  3  
  4  procedure it
  5  as
  6  begin
  7      who_called_me( g_owner, g_name, g_lineno, g_caller_t );
  8  end;
  9  
 10  
 11  end;
 12  /

Package body created.

ops$tkyte@ORA815.US.ORACLE.COM> 
ops$tkyte@ORA815.US.ORACLE.COM> 
ops$tkyte@ORA815.US.ORACLE.COM> drop table t;

Table dropped.

ops$tkyte@ORA815.US.ORACLE.COM> 
ops$tkyte@ORA815.US.ORACLE.COM> 
ops$tkyte@ORA815.US.ORACLE.COM> create table t
  2  ( x int constraint check_x check (x>0),
  3    y int constraint check_y check (y>0)
  4  );

Table created.

ops$tkyte@ORA815.US.ORACLE.COM> 
ops$tkyte@ORA815.US.ORACLE.COM> create or replace procedure p( p_x in int, p_y in int )
  2  as
  3  begin
  4      mark.it;
  5      insert into t values ( p_x, p_y );
  6      mark.it;
  7      update t set y = -p_y where x = p_x;
  8  exception
  9      when others then
 10          dbms_output.put_line( 'Error on line ' || mark.g_lineno ||
 11                                ' of ' || mark.g_caller_t || ' ' ||
 12                                mark.g_owner || '.' || mark.g_name );
 13  end;
 14  /

Procedure created.

ops$tkyte@ORA815.US.ORACLE.COM> 
ops$tkyte@ORA815.US.ORACLE.COM> exec p(1,1)
Error on line 6 of PROCEDURE OPS$TKYTE.P

PL/SQL procedure successfully completed.

ops$tkyte@ORA815.US.ORACLE.COM> exec p(-1,-1)
Error on line 4 of PROCEDURE OPS$TKYTE.P

PL/SQL procedure successfully completed.
 

A reader, November 13, 2001 - 10:19 am UTC

Tom,

I ran your procedure script, but it failed since the objects sys.plsql_trace_events, sys.plsql_trace_runnumber are not there in SYS schema.

Is there any script file to create these objects?...

Thanks.

Tom Kyte
November 13, 2001 - 10:26 am UTC

in 816 and up:

@tracetab.sql
@dbmspbt.sql
@prvtpbt.plb

when connected as SYS ( or internal, or "as sysdba" ).

in 815 only:

@dbmspbt.sql
@prvtpbt.plb

when connected as SYS ( or internal, or "as sysdba" )

as there aren't any trace tables. These are found in $ORACLE_HOME/rdbms/admin

can DBMS_TRACE be called from PL/SQL ?

Philippe, June 04, 2002 - 4:20 pm UTC

Hi Tom !

I'm trying to set the trace ON from a PL/SQL procedure and it doesn't seem to work (no events in PLSQL_TRACE_EVENTS).

Here is my test case :

--==================================================
CREATE OR REPLACE PROCEDURE traceexc AS
l_runid NUMBER;
BEGIN
SELECT sys.plsql_trace_runnumber.CURRVAL
INTO l_runid
FROM DUAL;

FOR x IN (SELECT *
FROM sys.plsql_trace_events
WHERE runid = l_runid AND event_kind =
DBMS_TRACE.plsql_trace_excp_raised
ORDER BY event_seq DESC) LOOP
DBMS_OUTPUT.put_line (
'Exception '
|| x.excp
|| '('
|| SQLERRM (SQLCODE)
|| ') occured in '
|| x.event_unit_kind
|| ' '
|| x.event_unit_owner
|| '.'
|| x.event_unit
|| ' at line '
|| x.event_line
);
EXIT;
END LOOP;
END;
--==================================================
CREATE OR REPLACE PROCEDURE testexc AS
BEGIN
EXECUTE IMMEDIATE 'insert into tototata values (1,12)'; -- Will raise an
exception
EXCEPTION
WHEN OTHERS THEN
traceexc;
raise;
END testexc;
--==================================================
CREATE OR REPLACE PROCEDURE test AS
BEGIN
DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_exceptions);
testexc;
END test;
--==================================================


Any idea on how to enable DBMS_TRACE from PL/SQL ?

Thanks in advance !



Tom Kyte
June 05, 2002 - 6:26 am UTC

do it as i did it -- I did trace on AND THEN ran the code.  You are

"turning on trace, run the code"

It is my experience that you have to turn on trace and then it will affect all SUBSEQUENT runs of code, not the currently executing piece of code.


ops$tkyte@ORA817DEV.US.ORACLE.COM> CREATE OR REPLACE PROCEDURE test AS
  2  BEGIN
  3     DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_exceptions);
  4     testexc;
  5  END test;
  6  /

Procedure created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec test
BEGIN test; END;

*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "OPS$TKYTE.TESTEXC", line 7
ORA-06512: at "OPS$TKYTE.TEST", line 4
ORA-06512: at line 1


ops$tkyte@ORA817DEV.US.ORACLE.COM> 
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec   DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_exceptions);

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> CREATE OR REPLACE PROCEDURE test AS
  2  BEGIN
  3     testexc;
  4  END test;
  5  /

Procedure created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec test
Exception 942(ORA-00942: table or view does not exist) occured in PROCEDURE OPS$TKYTE.TESTEXC at line 3
BEGIN test; END;

*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "OPS$TKYTE.TESTEXC", line 7
ORA-06512: at "OPS$TKYTE.TEST", line 3
ORA-06512: at line 1 

I have to set_trace in PL/SQL...

Philippe, June 05, 2002 - 9:56 am UTC

I did some more tests... and if, in my test procedure I set the trace to the trace_all_calls level i.e.

DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_calls);

then I get a full trace (including exceptions).

As my procedure is submitted as a JOB I think I need to set the trace in the procedure itself...

I also noticed that the trace contains a lot of

PL/SQL Virtual Machine started
PL/SQL Virtual Machine stopped

events... what's that ?

Tom Kyte
June 05, 2002 - 12:34 pm UTC

each stack built/unbuilt (new scope) will tend to do that.

what about the difference between trace levels ?

Philippe, June 06, 2002 - 1:49 am UTC

What about the fact that a set trace at trace_all_calls level i.e.

DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_calls);

generates full trace (including exceptions) BUT a trace set (at the same place) at trace_all_exceptions level doesn't generate trace for raised exceptions ??



Tom Kyte
June 06, 2002 - 7:24 am UTC

For this one, you'll have to open a TAR with support to see if it is

a) supposed to do that.
b) an issue that needs to be corrected.



A reader, June 06, 2002 - 8:49 am UTC

Tom,
TABLE sys.plsql_trace_events does not exits.
We are using 8.1.7

I have "select any table" privileges

SQL> desc sys.plsql_trace_events;
ERROR:
ORA-04043: object sys.plsql_trace_events does not exist
  

Tom Kyte
June 06, 2002 - 9:10 am UTC

see $ORACLE_HOME/rdbms/admin/tracetab.sql (or the docs)

</code> http://docs.oracle.com/docs/cd/A87860_01/doc/appdev.817/a76936/dbms_tra.htm#998100 <code>

Suggest you read the docs regardless (although I just now notice there is a doc bug, they say SYSTEM in the docs, but the script correctly says and does SYS)



Problem in creating udump

Siva, August 13, 2002 - 2:00 am UTC

Hello TOM,
        As you mentioned in the script i ran the oracle (/admin folder)  scripts and your sample example.
        I got the following entries. But This file is not created in the udump folder.
        Is there any problem in My setting. 
        Platform : Oracle 9.0.1 on WIN98.



SQL>  select c.value || '\' || instance || '_ora_' ||
  2          ltrim(to_char(to_number(a.spid),'fm99999999999999')) || '.trc'
  3     from sys.v$process a, sys.v$session b, sys.v$parameter c, sys.v$thread c
  4    where a.addr = b.paddr
  5      and b.audsid = userenv('sessionid')
  6      and c.name = 'user_dump_dest'
  7  /

C.VALUE||'/'||INSTANCE||'_ORA_'||LTRIM(TO_CHAR(TO_NUMBER(A.SPID),'FM999999999999
--------------------------------------------------------------------------------
c:\oracle\admin\siva\udump\siva_ora_-658843.trc
c:\oracle\admin\siva\udump\siva_ora_-659555.trc
c:\oracle\admin\siva\udump\siva_ora_-667303.trc
c:\oracle\admin\siva\udump\siva_ora_-646979.trc
c:\oracle\admin\siva\udump\siva_ora_-649015.trc
c:\oracle\admin\siva\udump\siva_ora_-651179.trc
c:\oracle\admin\siva\udump\siva_ora_-734359.trc
c:\oracle\admin\siva\udump\siva_ora_-207687.trc



If i will get one entry and run the procedure i got the following error. I think this file
is not exists.


SQL> exec p(1,1);
BEGIN p(1,1); END;

*
ERROR at line 1:
ORA-22288: file or LOB operation FILEOPEN failed
The system cannot find the file specified.
ORA-06512: at "SYS.DBMS_LOB", line 475
ORA-06512: at "SYS.P", line 22
ORA-02290: check constraint (SYS.CHECK_Y) violated
ORA-06512: at line 1


regards,
siva 

Tom Kyte
August 13, 2002 - 8:37 am UTC

Look at the file names generated by that query.

See how the spid is negative apparently.

You'll have to look at v$process and at what is actually in the file system and correct the query for your specific version on your specific platform.

The generated filenames are obviously wrong -- you need to correct that first

Retreiving call stuck from exception

Sasa Petkovic, August 13, 2002 - 7:28 am UTC

Hi Tom,

Please could you answer me how to find original call stuck when the exception occured?

Regards

Sasa

Tom Kyte
August 13, 2002 - 5:01 pm UTC

call "stack" perhaps.

You can get the call stack using dbms_utility.format_call_stack -- BUT it'll be the call stack from the perspective of the exception handler.

That is it, that is the only thing you have access to. Nothing more, nothing less.

But how ADO or TOAD get the call stack ..?

Sasa Petkovic, August 14, 2002 - 5:52 am UTC

Hi Tom,

You answered about call stack :
"You can get the call stack using dbms_utility.format_call_stack -- BUT it'll be
the call stack from the perspective of the exception handler."

We know about dbms_utility.format_call_stack and in a some way it is not correct, because it shows only the path to the exception handler not to place where the real exception occurred .
We want to know how TOAD or ADO get the "real" call stack?

Thanks

Sasa

Tom Kyte
August 14, 2002 - 8:04 am UTC

A client application gets the full error stack cause the error is propagated out.

Once you have an exception block in PLSQL and catch the exception -- the error goes away, it by very definition doesn't exist. You caught it, you are dealing with it, you are handling it.

So, if you let the error propagate to the client, they get an error stack (we have an error)

If you catch the error in plsql, the error is gone, you just erased it.

That is how toad (a client application) gets it.

Finally one "mistery " is resolved.

Sasa, August 15, 2002 - 12:57 pm UTC

Thanks a lot Tom.

As usually you were brilliant.

Regards,

Sasa

DBMS_TRACE exceptions inside PLSQL

Raghid Ajamoughli, September 20, 2002 - 3:32 pm UTC

Tom

I am able to get DBMS_TRACE to catch exceptions inside PL/SQL Block, here is how:
I used "dbms_trace.plsql_trace_excp_handled" instead of
"dbms_trace.trace_all_exceptions"

for example:
procedure test as
begin
dbms_trace.set_plsql_trace(dbms_trace.plsql_trace_excp_handled);
p(1,1);
dbms_trace.clear_plsql_trace;
end;

I do not know of any implications, but I would appreciate if someone at Oracle can confirm this method.

Thanks
Raghid Ajamoughli




It's most useful! But ..

Li ys, June 12, 2003 - 5:39 am UTC

It's most useful indeed,But I think I can't use it in my situation.I want to exec a huge *.sql file in SQL*PLUS,and want to trap the problematic statement,I use the 'WHENEVER SQLERROR EXIT' and 'spool some.log',but this log file have not the problematic statement and only the error code,so I can't catch which statement error by log.

And,The sql file is too huge,It contains statements such as:
'create table ...','insert into ...',eg.So I also can't use 'begin.. end.. exception.. ' like you said above.

Unless I write 'begin.. end.. exception..' by each statement such as 'insert',But It's too huge to act.

If can use 'WHENEVER SQLERROR EXIT pl/sql' is so good,but I know it's impossible,Could you give me directions?

Thanks a lot!

Tom Kyte
June 12, 2003 - 8:56 am UTC

sqlplus you see is a very simple command line tool for running simple scripts.

It was never really designed as an "installation tool".

sounds like you want to have an installation tool. You can use OUI (oracle universal installer) or DIY (do it yourself).

For example, put your sql in a very simple delimited file. Write a simple small program to read that file and execute the SQL. You now have complete control over what it does.

You can even write this program in PLSQL and use a BFILE or UTL_FILE to read the SQL and dynamically execute it. (BFILE would be good, won't require a reboot of the server if you don't have utl_file_dir set, although in 9iR2, utl_file can use a directory object instead of utl_file_dir so in that relate, utl_file would be the way to go)



Great Thread

Mike Schmidt, July 24, 2003 - 2:29 pm UTC

> Once you have an exception block in PLSQL and catch
> the exception -- the error goes away, it by very
> definition doesn't exist. You caught it, you are
> dealing with it, you are handling it.

I've often wondered if there is any way to force the error number into a trace file (e.g. ERROR #c:err=e tim=t) even though an exception handler is catching and handling the exception and not re-raising it. This would be good evidence to show an inexperienced developer the error that was thrown (and then ignored) in the developer's WHEN OTHERS THEN ... handler.


Tom Kyte
July 24, 2003 - 4:30 pm UTC

search for

dbms_trace

on this site (yes)

whats the eebsite address of ur friend to whom we can ask architectural questions, about java etc

A reader, July 24, 2003 - 11:34 pm UTC


Tom Kyte
July 25, 2003 - 7:05 am UTC

devtrends.oracle.com

thanx Tom!

A reader, August 20, 2003 - 2:50 pm UTC

I am a little confused about using of debug.f package
of yours versus dbms_trace method that you explained above.
Are the complements to each other - and if so in what
way. I think that one could use debug.f in the following
ways:

1. To know where exactly you are in the procedure - to
see the info on what is happenning in sequence
2. To "time" the procedures. - Since time is
automatically generated - this may not be an issue -
You could also do it using dbms_utility.get_time
and debug.f the times it took
So debug.f - helps mainly in non-exception errors
and performance tracking/problems

You would use dbms_trace to trace exceptions - Not
all errors are exceptions -


hence you need both. Is this analysis correct?

Thanx!!

Tom Kyte
August 21, 2003 - 5:06 pm UTC



dbms_trace is an internal, supplied package that can perform a rudimentary trace of your plsql code -- what happened where and so on.

debug.f is just a way for you to create your own custom tracing -- like a personal "sql_trace=true"

with debug.f, you can:

debug.f( 'in routine foo, x = %s, y = %s', x, y );

you won't get stuff like that from dbms_trace. with dbms_trace you'll get stuff you cannot possibly print out with debug.f (like the actual line number an exception was raised on originally)



I hate PL/SQL exception handling

Dan Loomis, June 03, 2004 - 5:03 pm UTC

Actually, hate is a strong word, but I wish it were more like Java-type exceptions. I understand that the exception stack trace disappears when the code enters an exception handler, but I disagree that having the stack trace is no longer necessary. There are many times I have to catch an error in WHEN OTHERS, only to do some logging, closing cursors, and other cleanup-type activities. I understand (but don't agree) why I can't throw the same exception with an intact stack trace, but it still baffles me why I can at least have access to the entire stack trace via some system variable, like sqlerrm. For example:

create or replace procedure c

is

l_number number;

begin

--cause error here
l_number := 1/0;

end;
/

create or replace procedure b

is

begin

c;

end;
/

create or replace procedure a

is

begin

b;

exception
when others then
--mandatory cleanup, like closing cursors.
--I want to log the stack trace here! How?
--and optionally reraise to the client.
raise;

end;
/

Great discussion by the way....

How to interpret the result of dbms_trace

Sean, July 14, 2004 - 12:27 pm UTC

Hi Tom,

Now we know we can use dbms_trace to track exception.  But How do I use it for other purpose?

I read the package guide, but it didn't give any exmpales to interpret the result.  I got some query  from other web site, but it is not very useful.  Here is what I tried.

The reason I am asking is that PL/SQL user's guide always mentions this package, but it seems that it is so difficult to interpret the result.


------------------------------------------------------------------------

SQL> exec DBMS_TRACE.set_plsql_trace (DBMS_TRACE.trace_all_calls);

PL/SQL procedure successfully completed.

-- Got this code from your "Expert" book
SQL> create or replace
  2  function fact_recursive( n int ) return number
  3  as
  4  begin
  5          if ( n = 1 )
  6          then
  7                  return 1;
  8          else
  9                  return n * fact_recursive(n-1);
 10          end if;
 11  end;
 12  /

Function created.

SQL> begin
  2   for i in 1 .. 50 loop
  3    dbms_output.put_line( fact_recursive(50) );
  4   end loop;
  5  end;
  6  /

PL/SQL procedure successfully completed.


SQL> exec DBMS_TRACE.clear_plsql_trace;

PL/SQL procedure successfully completed.



SQL> ed
Wrote file afiedt.buf

  1  SELECT r.runid,
  2         TO_CHAR(r.run_date, 'DD-MON-YYYY HH24:MI:SS') AS run_date,
  3         r.run_owner
  4  FROM   sys.plsql_trace_runs r
  5* ORDER BY r.runid
SQL> /

     RUNID RUN_DATE             RUN_OWNER
---------- -------------------- -------------------------------
         8 14-JUL-2004 12:07:17 SCOTT

1 rows selected.

-- I got this query from other site.  But useless in this case.
>SELECT e.runid,
       e.event_seq,
       TO_CHAR(e.event_time, 'DD-MON-YYYY HH24:MI:SS') AS event_time,
       e.event_unit_owner,
       e.event_unit,
       e.event_unit_kind,
       e.proc_line,
       e.event_comment
FROM   sys.plsql_trace_events e
WHERE  e.runid = 8
ORDER BY e.runid, e.event_seq;
 

Tom Kyte
July 14, 2004 - 9:52 pm UTC

ok, what part isn't "clear" really? I mean, it is just showing you what happened in the plsql, blow by blow?

How to use dbms_trace

Sean, July 15, 2004 - 7:41 am UTC

Hi Tom,

The question is really how to use dbms_trace properly to get the useful information which can not be got from other tools. I tried, but donÂ’t know how to interpret the result. I guess it may be the wrong way to use this package.

Or how do you use this package for your daily work besides tracking exception? If possible, give us an example, such as using trace_all_calls.

Thanks so much for your help.




Tom Kyte
July 15, 2004 - 12:41 pm UTC

tell me what you are trying to get. all it will do it show you "hey, this happened on this line of this source code file"

i find it useful to find where an exception happened -- thats about it.

I've never used it for anything else.

dbms_trace for tracking exception.

Sean, July 15, 2004 - 4:25 pm UTC

Hi Tom,

This is "REALLY" what I want to hear.

Thanks so much for your help.

Sean

DBMS_TRACE through DBMS_JOB.RUN

Mohini, August 19, 2004 - 2:05 pm UTC

Oracle 9.2.0.5 on HP UX

Hi Tom,
I created this test scenerio..where I wanted to see the line number using your method of
tracing all the exceptions.
For some reason..it did not work for me when I tried to use it through a DBMS_JOB.RUN:

CREATE TABLE DBA_LOG
(
LOGID NUMBER NOT NULL,
LOGDS VARCHAR2(500) NOT NULL,
STARTDT DATE,
ENDDT DATE,
NOTES VARCHAR2(255)
)
TABLESPACE TS_SMALL;

ALTER TABLE DBA_LOG ADD (
CONSTRAINT PK_DBA_LOG PRIMARY KEY (LOGID)
USING INDEX
TABLESPACE TS_IDX_SMALL);

CREATE SEQUENCE DBA_LOGID INCREMENT BY 1
START WITH 1 NOCYCLE
NOCACHE ORDER;


CREATE OR REPLACE
PACKAGE DEPT_PROC
AS

PROCEDURE DEPT_INSERT (pDEPTNO NUMBER);

END DEPT_PROC;

/

CREATE OR REPLACE
PACKAGE BODY DEPT_PROC
AS

PROCEDURE DEPT_INSERT (pDEPTNO NUMBER)
AS
BEGIN

INSERT INTO DEPT (DEPTNO,DNAME)
VALUES (pDEPTNO, 'TEST');

END DEPT_INSERT;

END DEPT_PROC;

/

CREATE OR REPLACE
PROCEDURE INSERT_DEPT (pDEPTNO NUMBER)
AS
BEGIN

DEPT_PROC.DEPT_INSERT (pDEPTNO);

END INSERT_DEPT;

/


CREATE OR REPLACE
PROCEDURE LOG_EXCEPTION
AS
L_RUNID NUMBER;
ERRORDS_V DBA_LOG.LOGDS%TYPE;
NOTES_V DBA_LOG.NOTES%TYPE;

BEGIN
SELECT SYS.PLSQL_TRACE_RUNNUMBER.CURRVAL INTO L_RUNID
FROM DUAL;

FOR X IN ( SELECT *
FROM SYS.PLSQL_TRACE_EVENTS
WHERE RUNID = L_RUNID
AND EVENT_KIND = 52
ORDER BY EVENT_SEQ DESC )
LOOP
ERRORDS_V := 'Exception occured in source ' ||
X.EVENT_UNIT || ' ' || X.EVENT_UNIT_KIND ||
' on line ' || X.EVENT_LINE;
NOTES_V := SUBSTR(SQLERRM, 1, 200);

DBMS_OUTPUT.PUT_LINE( ERRORDS_V);

DBMS_OUTPUT.PUT_LINE( NOTES_V);
--DBMS_OUTPUT.PUT_LINE( 'Error Code ' || SQLCODE);

INSERT INTO DBA_LOG (LOGID, LOGDS, STARTDT, NOTES)
VALUES (DBA_LOGID.NEXTVAL, ERRORDS_V, SYSDATE, NOTES_V);

EXIT;
END LOOP;
END LOG_EXCEPTION;

/


CREATE OR REPLACE PROCEDURE TEST_EXCP_PROC
AS
BEGIN

INSERT_DEPT (10);

INSERT INTO DEPT (DEPTNO,DNAME)
VALUES (50, 'TEST');

END TEST_EXCP_PROC;
/


CREATE OR REPLACE PROCEDURE TEST_EXCP_PROC_RUN
AS

BEGIN

TEST_EXCP_PROC;

EXCEPTION
WHEN OTHERS THEN
LOG_EXCEPTION;

END TEST_EXCP_PROC_RUN;
/

set serveroutput on;

SELECT * FROM DBA_LOG;
execute dbms_trace.set_plsql_trace( dbms_trace.trace_all_exceptions );
execute TEST_EXCP_PROC_RUN;
SELECT * FROM DBA_LOG;

/*Output from the above:

SQLWKS> set serveroutput on;
Server Output ON
SQLWKS>
SQLWKS> SELECT * FROM DBA_LOG;
LOGID LOGDS STARTDT ENDDT NOTES
---------- -------------------------------------------------------------------------------- -------------------- -------------------- --------------------------------------------------------------------------------
0 rows selected.
SQLWKS> execute dbms_trace.set_plsql_trace( dbms_trace.trace_all_exceptions );
Statement processed.
SQLWKS> execute TEST_EXCP_PROC_RUN;
Statement processed.
Exception occured in source DEPT_PROC PACKAGE BODY on line 8
ORA-00001: unique constraint (MDBA.PK_DEPT) violated
SQLWKS> SELECT * FROM DBA_LOG;
LOGID LOGDS STARTDT ENDDT NOTES
---------- -------------------------------------------------------------------------------- -------------------- -------------------- --------------------------------------------------------------------------------
1 Exception occured in source DEPT_PROC PACKAGE BODY on line 8 19-AUG-04 ORA-00001: unique constraint (MDBA.PK_DEPT) violated
1 row selected.

*/


--Now let's try to run this through a job..in another session

TRUNCATE TABLE DBA_LOG;

CREATE OR REPLACE PROCEDURE TEST_EXCP_PROC_RUN
AS

BEGIN

dbms_trace.set_plsql_trace( dbms_trace.trace_all_exceptions );
TEST_EXCP_PROC;

EXCEPTION
WHEN OTHERS THEN
LOG_EXCEPTION;

END TEST_EXCP_PROC_RUN;
/


DECLARE
X NUMBER;
BEGIN
SYS.DBMS_JOB.SUBMIT
( job => X
,what => 'TEST_EXCP_PROC_RUN;'
,next_date => trunc(sysdate+1)+17/96
,interval => 'trunc(sysdate+1)+17/96'
,no_parse => TRUE
);
COMMIT;
END;
/

SELECT JOB,WHAT FROM USER_JOBS

/*

JOB WHAT
---------- -------------------------
63 TEST_EXCP_PROC_RUN;
1 row selected.

*/


set serveroutput on;
SELECT * FROM DBA_LOG;
EXECUTE DBMS_JOB.RUN(63);
SELECT * FROM DBA_LOG;

/*

SQLWKS> set serveroutput on;
Server Output ON
SQLWKS> SELECT * FROM DBA_LOG;
LOGID LOGDS STARTDT ENDDT NOTES
---------- -------------------------------------------------------------------------------- -------------------- -------------------- --------------------------------------------------------------------------------
0 rows selected.
SQLWKS> EXECUTE DBMS_JOB.RUN(63);
Statement processed.
SQLWKS> SELECT * FROM DBA_LOG;
LOGID LOGDS STARTDT ENDDT NOTES
---------- -------------------------------------------------------------------------------- -------------------- -------------------- --------------------------------------------------------------------------------
0 rows selected.

*/

So, Nothing gets logged in DBA_LOG table..
Is there a way around this..

Thanks.









Tom Kyte
August 19, 2004 - 5:32 pm UTC

not that i know of the dbms_trace has to take place and then the next code executed will be using it.

in this case, the BEST thing to do is remove any and all "non useful" exception blocks.

exceptions should be caught IF and ONLY IF you

a) expect them
b) can do something about them

eg: when no_data_found -- catch it, deal with it.


other exceptions that you cannot possibly recover from should not be caught and the job queues will absolutely record the line number and everything exactly right in the alert log.

great thread

riaz shahid, August 19, 2004 - 6:35 pm UTC

and here i would like to quote the TOM's saying:

"i wish When Others exception doesn't exist"

who_called_me correction

A reader, November 01, 2004 - 8:40 pm UTC

This is in reference to procedure who_called_me at
</code> http://asktom.oracle.com/~tkyte/who_called_me/index.html <code>

In 10.1.0.3, this procedure gives an error because of
slight change in format call stack.
Only change is in the line
lineno := to_number(substr( line, 13, 6 ));
that changes to
lineno := to_number(substr( line, 13, 8 ));
Changed method follows (tested it quickly with 9i and 10gr1 - you may want to test it out more thoroughly:)):
---
create or replace procedure who_called_me( owner out varchar2,
name out varchar2,
lineno out number,
caller_t out varchar2 )
as
call_stack varchar2(4096) default dbms_utility.format_call_stack;
n number;
found_stack BOOLEAN default FALSE;
line varchar2(255);
cnt number := 0;
begin
--
loop
n := instr( call_stack, chr(10) );
exit when ( cnt = 3 or n is NULL or n = 0 );
--
line := substr( call_stack, 1, n-1 );
call_stack := substr( call_stack, n+1 );
--
if ( NOT found_stack ) then
if ( line like '%handle%number%name%'
) then
found_stack := TRUE;
end if;
else
cnt := cnt + 1;
-- cnt = 1 is ME
-- cnt = 2 is MY Caller
-- cnt = 3 is Their Caller
if ( cnt = 3 ) then
lineno := to_number(substr( line, 13, 8 ));
line := substr( line, 21 );
if ( line like 'pr%' ) then
n := length( 'procedure ' );
elsif ( line like 'fun%' ) then
n := length( 'function ' );
elsif ( line like 'package body%' ) then
n := length( 'package body ' );
elsif ( line like 'pack%' ) then
n := length( 'package ' );
elsif ( line like 'anonymous%' ) then
n := length( 'anonymous block ' );
else
n := null;
end if;
if ( n is not null ) then
caller_t := ltrim(rtrim(upper(substr( line, 1, n-1 ))));
else
caller_t := 'TRIGGER';
end if;

line := substr( line, nvl(n,1) );
n := instr( line, '.' );
owner := ltrim(rtrim(substr( line, 1, n-1 )));
name := ltrim(rtrim(substr( line, n+1 )));
end if;
end if;
end loop;
end;
/

create or replace function who_am_i return varchar2
is
l_owner varchar2(30);
l_name varchar2(30);
l_lineno number;
l_type varchar2(30);
begin
who_called_me( l_owner, l_name, l_lineno, l_type );
return l_owner || '.' || l_name;
end;
/
-----
Thanx.

Tom Kyte
November 02, 2004 - 7:16 am UTC

thanks for the update!

dbms_trace in 9i (9.2.0.1.0)

Menon, December 06, 2004 - 10:07 am UTC

I have two questions:
1. Are the different event kinds documented anywhere?
2. dbms_trace does nt seem to work for me in 9.2.0.1.0...
The same works for me in 10g r1. Is this a known bug?
---------
benchmark@ORA92I> create or replace procedure p3
2 is
3 l_x number := 0;
4 begin
5 dbms_output.put_line( 'p3' );
6 l_x := 1/ l_x; -- divide by zero
7 end;
8 /

Procedure created.

benchmark@ORA92I> show errors;
No errors.
benchmark@ORA92I> create or replace procedure p2
2 is
3 begin
4 dbms_output.put_line( 'p2' );
5 p3;
6 end;
7 /

Procedure created.

benchmark@ORA92I> show errors;
No errors.
benchmark@ORA92I> -- use dbms_trace
benchmark@ORA92I> -- procedure for printing dbms_trace info
benchmark@ORA92I> -- requires select on plsql_trace_events and plsql_trace_runnumber
benchmark@ORA92I> create or replace procedure print_dbms_trace
2 is
3 l_runid binary_integer;
4 begin
5 select sys.plsql_trace_runnumber.currval
6 into l_runid
7 from dual;
8 for x in ( select *
9 from sys.plsql_trace_events
10 where runid = l_runid
11 and event_kind = 52
12 order by event_seq DESC )
13 loop
14 dbms_output.put_line( 'Exception occured in source ' ||
15 x.event_unit ||
16 ' on line ' || x.event_line );
17 exit;
18 end loop;
19 end;
20 /

Procedure created.

benchmark@ORA92I> show errors;
No errors.
benchmark@ORA92I> create or replace procedure p1
2 is
3 begin
4 dbms_output.put_line( 'p1 (using dbms_trace - trace_all_exceptions)' );
5 dbms_trace.set_plsql_trace( dbms_trace.trace_all_exceptions );
6 p2;
7 dbms_trace.clear_plsql_trace;
8 exception when others then
9 print_dbms_trace;
10 raise;
11 end;
12 /

Procedure created.

benchmark@ORA92I> show errors;
No errors.
benchmark@ORA92I> alter session set plsql_debug = true;

Session altered.

benchmark@ORA92I> alter procedure p1 compile debug;

Procedure altered.

benchmark@ORA92I> --exec dbms_trace.set_plsql_trace( dbms_trace.trace_all_exceptions );
benchmark@ORA92I> exec p1
p1 (using dbms_trace - trace_all_exceptions)
p2
p3
BEGIN p1; END;

*
ERROR at line 1:
ORA-01476: divisor is equal to zero
ORA-06512: at "BENCHMARK.P1", line 10
ORA-06512: at line 1


Tom Kyte
December 06, 2004 - 12:32 pm UTC

1) support gives them out as needed. they are dangerous in general as they change over time.

2)if you do it in the manner i did above (calling trace outside the block), what then

correction

Menon, December 06, 2004 - 11:15 am UTC

In the above run, I ran the dbms_trace.set* inside the
PL/SQL block. I tried running it outside as well before
posting the results - it had not worked.

shoul it be in the same session ?

A reader, December 06, 2004 - 1:40 pm UTC


Tom Kyte
December 06, 2004 - 1:55 pm UTC

yes

How much impact does dbms_trace have on performance

Raja, June 14, 2005 - 1:39 pm UTC

Hi Tom,
Can you tell if there is any impact the dbms_trace.set_plsql_trace has on performance of the code.

Thanks,
-Raja

Tom Kyte
June 14, 2005 - 4:17 pm UTC

one word for you:

benchmark


you can do it! you might use

</code> http://asktom.oracle.com/~tkyte/runstats.html <code>



Thanks!

A reader, June 14, 2005 - 4:50 pm UTC

Hi Tom,
Your reply is highly appreciated. I will benchmark and see where we stand.

-Raja

dbms_utility.format_call_stack

William Wong, June 22, 2005 - 9:53 am UTC

I like this topic. I have written a package procedure to return the stack information using dbms_utility.format_call_stack whenever there is an error. It works fine when called from PLSQL block within proC, sqlplus or TOAD. But the stack is null when the package is called from a form. I am running Oracle 9.2.0.4, but forms 6i. Is it a problem with the PLSQL version of forms 6i not supporting that ? If not, can you think of any reason ?


Tom Kyte
June 22, 2005 - 4:38 pm UTC

well, if you call directly from forms, there is "no call stack" other than the call to dbms_utility?

the forms call stack isn't known in the database at all, that is where dbms_utility is living.

Call stack

William Wong, June 22, 2005 - 5:05 pm UTC

Let me clarify, I call a database package that performs a select from a table. When no data found, the procedure calls another package function that gets the stack and return the stack information, which shows the name of the validation package. In the forms, I am not able to refer to DBMS_UTILITY.FORMAT_CALL_STACK directly, it will not compile.


Tom Kyte
June 23, 2005 - 1:51 pm UTC

for forms issues, i'll have to refer you elsewhere -- i haven't used it in a decade.

sorry.

Call Stack

William Wong, June 22, 2005 - 5:42 pm UTC

In fact, I tried your procedure who_called_me and function who_am_i. I have the following in a form ON-NEW-FORM-INSTANCE trigger:
emessage('>>'||demof);

All I got is
>> . line

demof is similar to your demo procedure as below:
create or replace function demof return varchar2 as
begin
return who_am_i;
end;

I can get
FUNCTION bssrd05.DEMOF line 3
if call it from a PLSQL block in sqlplus or TOAD.

Not exactly 8i, but still

Mikito Harakiri, June 22, 2005 - 6:07 pm UTC

SQL> desc v$session
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 SADDR                                              RAW(4)
 SID                                                NUMBER
 SERIAL#
blah blah blah                                            NUMBER
 SQL_ADDRESS                                        RAW(4)
 SQL_HASH_VALUE                                     NUMBER
 SQL_ID                                             VARCHAR2(13)
 SQL_CHILD_NUMBER                                   NUMBER
 PREV_SQL_ADDR                                      RAW(4)
 PREV_HASH_VALUE
-^^^^^^^^^^^^^^^                                    NUMBER
 PREV_SQL_ID                                        -^^^^^^^^^^^                                    NUMBER
VARCHAR2(13)
 PREV_CHILD_NUMBER                                  NUMBER
-^^^^^^^^^^^^^^^^^                                    
...
 

Tom Kyte
June 23, 2005 - 1:52 pm UTC

flesh it out, show us what you mean.

It's a 10g enhancement...

Adrian, June 23, 2005 - 5:51 pm UTC

Tom,

Hope you don't mind me stepping in. I'm sure you are aware that Mikito is referring to the inclusion of the SQL_ID, hash value etc of the previous SQL statement (cursor) executed in v$session. Seems to be mostly used as a default value for the SQL_ID parameter to DBMS_XPLAN.DISPLAY_CURSOR ( another 10g new feature ) to display actual execution plans ( unfortunately for you it replaces the DYNAMIC_PLAN_TABLE you had in your last book ! ). The various PREV_XXX values can also be used in lookups to V$SQL, V$SQL_PLAN etc.

Beware serveroutput though if you are in sqlplus, because if you have serveroutput on, then your PREV_XXX will be DBMS_OUTPUT.GET_LINES or some such like, and not the last SQL statement executed.

Regards
Adrian

Tom Kyte
June 23, 2005 - 7:43 pm UTC

and in a trigger or anything else -- what then....

point again:

got idea? flesh it out.

I know what is in the v$ views, if he has a "point" he'd demonstrate what he meant.

Using PREV_SQL_ADDR and PREV_HASH_VALUE

David, January 18, 2006 - 4:14 pm UTC

Tom,
I'm using this "AFTER SERVERERROR" trigger in SYS schema
(original written by Nico Booyse in 2000) to capture the application errors (Perl/java w/ connection polls)

Works well, the only issue is that the SQL statement captured end up being not the error statement but the trigger's select:

CREATE TABLE LOG_ERRORS_TAB (
ERROR VARCHAR2(30),
TIMESTAMP DATE,
USERNAME VARCHAR2(30),
OSUSER VARCHAR2(30),
MACHINE VARCHAR2(64),
PROCESS VARCHAR2(8),
PROGRAM VARCHAR2(48),
OBJ_TYPE VARCHAR2(50),
OBJ_NAME VARCHAR2(50),
SQL_TEXT VARCHAR2(1000));


CREATE OR REPLACE TRIGGER LOG_ERRORS_TRIG
AFTER SERVERERROR ON DATABASE
DECLARE
v_sql_addr RAW(4);
v_hash number;
BEGIN

select PREV_SQL_ADDR,PREV_HASH_VALUE into v_sql_addr,v_hash
from v$session where audsid = userenv('sessionid');

INSERT INTO log_errors_tab (error,timestamp,username, osuser, machine, process, program,obj_type, obj_name,sql_text)
SELECT dbms_standard.server_error(1),SYSDATE,username, osuser, machine, process, program,sys.dictionary_obj_type,sys.dictionary_obj_name, sql_text
FROM v$session s ,v$sqlarea a
WHERE a.ADDRESS= v_sql_addr
AND a.HASH_VALUE=v_hash
AND audsid = userenv('sessionid');
END;
/
show errors

SELECT error,sql_text FROM log_errors_tab ORDER BY timestamp ;

ERROR SQL_TEXT
------------- ------
54 SELECT PREV_SQL_ADDR,PREV_HASH_VALUE FROM V$SESSION WHERE AUDSID = USERENV('sessionid')

I'm I using PREV_SQL_ADDR,PREV_HASH_VALUE properly?

Thank you for your time,
David

Tom Kyte
January 19, 2006 - 12:27 pm UTC

Use Event Attribute Functions - ora_sql_txt

David, January 18, 2006 - 4:43 pm UTC

Nethermind,
usered your other posting to fix it :)
</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:1657308242210 <code>

CREATE OR REPLACE TRIGGER LOG_ERRORS_TRIG
AFTER SERVERERROR ON DATABASE
DECLARE
csql_text ora_name_list_t;
n NUMBER;
cSQL CLOB;
BEGIN
n:= ora_sql_txt(csql_text);
FOR I IN 1..N LOOP
cSQL:=cSQL||csql_text(i);
END LOOP;

INSERT INTO log_errors_tab (error,timestamp,username, osuser, machine, process, program,obj_type, obj_name,sql_text)
SELECT ora_server_error(1),SYSDATE,username, osuser, machine, process, program,ora_dict_obj_type,ora_dict_obj_name, cSQL
FROM v$session s
WHERE audsid = userenv('sessionid');
END;
/
show errors

Thanks!

Tom Kyte
January 19, 2006 - 12:27 pm UTC

ahh, I should read the entire page :)

Is it possible to use combination of DBMS_TRACE and Session tace

Shailesh Saraff, April 07, 2006 - 3:08 am UTC

Hello Tom,

Thanks for all your guidance. We use DBMS_TRACE, but currently I am finding few limitation for the same, please le us know if there is way out.

DBMS_TRACE shows output in SYS.PLSQL_TRACE_EVENTS table and it helps me to know how many triggers, procedures are invoked by my DML statements. As there are hundreds of Procedures, Triggers in our application it would be better if I get output as shown below...

Source Statement:
UPDATE TableName SET ColumnName = :1 WHERE ROWID = :2

Trigger: TrgRow_1

Procedure: Pro_1
SELECT ....
INSERT ....

Procedure: Pro_2
UPDATE
SELECT

This helps me to identify Statements related to corresponding Procedures or triggers. Currently We tried to club <sys.plsql_trace_events> and <user_source>, but still doesn't get output as shown above.

Please help.

Thanks & Regards,

Shailesh




ora-00600,

A reader, April 25, 2006 - 12:58 pm UTC

On a 10.2 database, we are executing a procedure directly on sqlPlus and calling it through asp page.

Lately (probalbly since morning), we are getting ora-00600 errors when we execute it through a asp page (but runs good on sqlPlus prompt).

This is what the trace file has
ksedmp: internal or fatal error
ORA-00600: internal error code, arguments: [kcbgcur_9], [4600202], [1], [4294967250], [2], [], [], []
Current SQL statement for this session:
INSERT INTO SYS.PLSQL_TRACE_EVENTS( RUNID, EVENT_TIME, EVENT_SEQ, EVENT_KIND, EVENT_COMMENT, STACK_DEPTH, EVENT_UNIT_DBLINK, EVENT_UNIT_OWNER, EVENT_UNIT, EVENT_UNIT_KIND, EVENT_PROC_NAME, EVENT_LINE, MODULE, ACTION, CLIENT_INFO, CLIENT_ID, ECID_ID, ECID_SEQ) VALUES(:B1, SYSDATE, :B2, :B3, :B4, :B5, :B6, :B7, :B8, :B9, :B10, :B11, :B12, :B13, :B14, :B15, :B16, :B17)


We don't know why we are getting this error.

One more question: What is the difference between the parameters sql_trace and trace_enabled?

We tried to set both to true and later to false and still we got ora 600 error.

Thanks,

Tom Kyte
April 25, 2006 - 2:29 pm UTC

ora-600 = please contact support.

ora 600,

A reader, April 25, 2006 - 3:19 pm UTC

We will try contacting support.

Why would the process inserts into SYS.PLSQL_TRACE_EVENTS? What is this table for?



Tom Kyte
April 25, 2006 - 11:50 pm UTC

you have enabled trace via a call to dbms_trace in your code.

Your code has asked for this to happen.

How to automate exception tracking in web application using DBMS_TRACE ?

Debashis Payin, May 18, 2006 - 8:18 am UTC

Hi Tom

Good Morning. I am having a problem while automating
PL/SQL Exception trace using DBMS_TRACE. We are working
on an web application which is having Oracle9iR2 as it's
DB. We are having some Stored Procedures for Back End
operations. Now, I want to track all the exceptions using
DBMS_TRACE. As per the way you've shown, I've written the
test code for that. But as it's a web application, I need
to do it in an automated way. Let me refresh in brief.
In our application, whenever any DB error(due to SPs etc.)
comes into piture, I need to catch that exception through
DBMS_TRACE package. But before making this package into
work, I need to run this package in the same session.
I've tried writing a DB startup trigger to do that in
the following way. But it's not supposed to work as this
has to run in the same session.

/*******************************************************/
CREATE OR REPLACE TRIGGER db_startup_dbms_trace_trigger
AFTER STARTUP ON DATABASE

BEGIN
DBMS_TRACE.SET_PLSQL_TRACE(DBMS_TRACE.TRACE_ALL_EXCEPTIONS);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error encountered -> ' || SQLCODE ||' , ' ||SQLERRM );
END;
/*******************************************************/

At the same time, I also can't do this in the body
of Stored Procedure.

Can you please give me a solution ? Please let me know
if I've failed to communicate the problem.

Thanks in advance for your time.

Thanks
Debashis
Bangalore

Tom Kyte
May 19, 2006 - 9:21 am UTC

why wouldn't the web application enable dbms_trace?

Thanks . One more query.

Debashis Payin, May 20, 2006 - 8:43 am UTC

Hi Tom

Thanks a lot. Just one more query related to your
answer : while connecting to DB from web application(java),
the developer can set DBMS_TRACE after connecting to DB, right ?
Or you are telling any other possiblity ?

Thanks
Debashis
Bangalore

Tom Kyte
May 20, 2006 - 5:00 pm UTC

yes, they can enable dbms_trace after connecting to the database.

Thanks !! There is one more possible solution, please suggest .

Debashis Payin, May 22, 2006 - 3:36 am UTC

Hi Tom

Thanks a lot for your response. There is one more
possible solution coming into my mind. If we create
a logon trigger like this, it's working fine? Can I use
this ? Or it might have any problem in future ? Please
give your suggestions/thoughts on this.

/********************************************************/

CREATE OR REPLACE TRIGGER ON_LOGON_DBMS_TRACE_TRIGGER
AFTER LOGON ON DATABASE
DECLARE
L_USER VARCHAR2(30);
BEGIN
SELECT USER
INTO L_USER
FROM DUAL ;
IF L_USER='DEV' THEN
DBMS_TRACE.SET_PLSQL_TRACE(DBMS_TRACE.TRACE_ALL_EXCEPTIONS);
END IF ;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error encountered -> ' || SQLCODE ||' , ' ||SQLERRM );
END;

/********************************************************/

Thanks
Debashis
Bangalore

Tom Kyte
May 22, 2006 - 7:51 am UTC

You can, as long as you are willing to accept the fact that upon failure, you have ignored the error and will be logged in anyway.

Also, if you ever start using a connection pool - all applications that use this session will be affected.


And you can sort of just code:


if user = 'DEV'
then
....
end if;


no need to query dual like that.

Reference to who_called_me

A reader, July 08, 2010 - 7:10 am UTC

The object handle returned from format_call_stack is longer on Linux than Unix and so these lines will fail:

In 10.1.0.3, this procedure gives an error because of
slight change in format call stack.
Only change is in the line
lineno := to_number(substr( line, 13, 6 ));
that changes to
lineno := to_number(substr( line, 13, 8 ));
Changed method follows (tested it quickly with 9i and 10gr1 - you may want to test it out more
thoroughly:)):

I created a generic parser for the line that is not column dependent.
Tom Kyte
July 08, 2010 - 12:50 pm UTC

I should mention that as of 9.2, this comes withthe database - you don't need "my code" anymore as they took that code and verify it for each release now.


owa_util.who_called_me

is a supplied package procedure.

Print Line Number with the Source Code of Object

Abhisek, August 03, 2010 - 6:35 am UTC

Hi Tom,

I would like to know if we can print the line numbers along with the source code. I tried for:

declare
var1 number := 0;
BEGIN
FOR cursor1 IN (SELECT line, text FROM user_source where NAME = 'MY_PACKAGE')
LOOP
var1 := var1+1;
if cursor1.text like '%PACKAGE BODY%'
THEN
DBMS_OUTPUT.PUT_LINE( var1 || ' ' || '/');
var1 := var1+1;
DBMS_OUTPUT.PUT_LINE( var1 || ' ' || cursor1.text);
ELSE
DBMS_OUTPUT.PUT_LINE( var1 || ' ' || cursor1.text);
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE( var1 || ' ' || '/');
END;
/


it works almost fine for Packages and Functions with some modification. But I would like to print the same for all types of objects: Tables, Views, Functions, Packages ....

I will paramterize them.. So is there any Oracle supplied package that is readily available. Please help in case we have to write new PL SQL to achive this.
Tom Kyte
August 03, 2010 - 8:48 am UTC

function, packages - just use the same technique - they are all in user source.


for 'tables' there isn't really any line number - you can use dbms_metadata.get_ddl to get the ddl - but they you would have to substr it based on end of line markers to get "line numbers"



A reader, October 05, 2010 - 12:48 pm UTC

Hi Tom,

As usual, thanks for your great site.

I have been testing same task in different style of queires to know which is better as per performance is considered (as you do-- test it and proove it).

Let me share you all the queries which does almost the same work.


Method 1: (This example i took from your one of the example)

declare
l_time pls_integer:= dbms_utility.get_time;
l_elapsed pls_integer;
cursor c1 is select emp_object(empno,ename) from emp;
l_emp emp_type; --emp_type is table of object
begin
open c1;
fetch c1 bulk collect into l_emp;
for a in 1..l_emp.count loop
l_emp(a).empname := l_emp(a).empname||'B';
insert into emp2(empno,ename) values(l_emp(a).empno,l_emp(a).empname);
end loop;
commit;

dbms_output.put_line('Here we go ah');
dbms_output.put_line(' The time taken is '||round((dbms_utility.get_time-l_time)/100,2));

end;



Method 2:

declare
/* procedure with plsql table*/
type e_record is record(empno number, ename varchar2(20));
type e_type is table of e_record index by binary_integer;
cursor c1 is select empno,ename from scott.emp;
--type emp_type as object (empno number,ename varchar2(20));
--type emp_table is table of emp_type index by binary_integer;
l_emp e_type;
l_time pls_integer:= dbms_utility.get_time;
l_elapsed pls_integer;
begin
open c1;
fetch c1 bulk collect into l_emp;
for a in 1..l_emp.count loop
l_emp(a).ename := l_emp(a).ename||'B';
insert into emp2(empno,ename) values(l_emp(a).empno,l_emp(a).ename);
end loop;
commit;
dbms_output.put_line(' The time taken is '||round((dbms_utility.get_time-l_time)/100,2));
end;





Method 3:
declare
/*loop manually*/
cursor c1 is select empno,ename from emp;
l_empno emp.empno%type;
l_ename emp.ename%type;
l_time pls_integer:= dbms_utility.get_time;
l_elapsed pls_integer;
begin
open c1;
loop
fetch c1 into l_empno,l_ename;
l_ename := l_ename||'B';
insert into emp2 (empno, ename) values (l_empno,l_ename);
exit when c1%notfound;
end loop;
commit;
dbms_output.put_line(' The time taken is '||round((dbms_utility.get_time-l_time)/100,2));
end;




Method 4:
declare
/* for loop*/
l_time pls_integer:= dbms_utility.get_time;
l_elapsed pls_integer;

begin
for a in (select empno,ename from emp) loop
a.ename := a.ename || 'B';
insert into emp2 (empno,ename) values (a.empno,a.ename);
end loop;
commit;
dbms_output.put_line(' The time taken is '||round((dbms_utility.get_time-l_time)/100,2));

end;


What i would like to know is that, if i execute first block and if the same query is used in any of the followed blocks then the query plan is saved and reused, so i would like to know all the things which i should do before starting the new block to test the performance.

Can you please suggest me what are all the things that i need to do before going to test a new type of block which may use the similar query used in the earlier block. Do i need to delete query plan or anything
Note: the above queries are just for sample, my intention is to know how we can proceed with such scenarios.

I posted the same question, at some forum and got the answer saying that i need to run multiple times the same query to have the correct result.
However, I would request your suggestions on it. How can i proceed with such scenarios.

Regards,

Tom Kyte
October 05, 2010 - 1:04 pm UTC

...I posted the same question, at some forum and got the answer saying that i need
to run multiple times the same query to have the correct result. ....

that is pretty much what I would have said as well...


the cost of that first hard parse, in a single user situation, it not going to skew the results massively one way or the other. You want to do a considerable amount of work (running the test a couple of times) and measure that (or at least do a very big test)

A reader, October 05, 2010 - 2:04 pm UTC

Thanks Tom.

Alex, November 30, 2011 - 10:43 am UTC

Hi Tom,
Great site.
I consider that your sustained work and effort give all of us a model to aim at and a proof that there is at least one place where knowledge is both priced and shared.

My problem is that I can't use BMS_UTLITY.FORMAT_CALL_STACK because of the Bug:5102847 (DBMS_UTLITY.FORMAT_CALL_STACK returns nothing when called via an RPC.)
Since its impossible to upgrade the database version at this time - high level decision - i must find another way to get that stack from plsql.
I'm pretty sure that this information is available during runtime in v$ tables or x$ "tables".
Can you please guide me where should I search next? (e.g. v$object_dependecy is close but not the same)
Thanks.
Tom Kyte
December 01, 2011 - 7:12 am UTC

there is no need for an upgrade, I see patches for 10.1, 10.2, 9i and so on.

it only affects forms - and it is the client side information that is missing - so nothing at all would be in any magic tables in the database.

More to Explore

CLOB/BLOB/etc

Complete documentation on Securefiles and Large Objects here