This is what I do, appologies to whoever this originally came from, I know I took it from some website, but can't remember where right now.
In preproduction, I have this
create table caught_errors (
dt date,
username varchar2( 30), -- value from ora_login_user
msg varchar2(2000),
stmt varchar2(2000)
);
create or replace trigger catch_errors
after servererror on database
declare
sql_text ora_name_list_t;
msg_ varchar2(2000) := null;
stmt_ varchar2(2000) := null;
begin
for depth in 1 .. ora_server_error_depth loop
msg_ := msg_ || ora_server_error_msg(depth);
end loop;
for i in 1 .. ora_sql_txt(sql_text) loop
stmt_ := stmt_ || sql_text(i);
end loop;
insert into
caught_errors (dt , username ,msg ,stmt )
values (sysdate, ora_login_user,msg_,stmt_);
end;
/
Any time servererror is thrown, its caught and logged to a table, I can then check that table to find the offending queries, and refund them as needed to see the missing table (when you run the query in sqlplus, it will tell you the table)
Note, yes, there is issues with this, eg, what if caught_errors is dropped, or raises an error itself, you could get recursive loop, hence why this only exists in preproduction.