A reader, January 06, 2011 - 3:29 pm UTC
Dear Sir,
Thanks for the advice.
This gives me the error details of the raise_application_error line and not actual line of error (v_environment_in := 'XX'; --here).
Also, since we are using DBMS_UTILITY.FORMAT_ERROR_STACK() & DBMS_UTILITY.FORMAT_ERROR_BACKTRACE to get the complete error details, we will check to see if Pro*C gives the same.
Thanks and keep up the good work.
Rakesh
--start sample code
/*
create or replace PROCEDURE t2(
p_environment_in IN VARCHAR2
)
IS
v_environment_in varchar2(1);
BEGIN
--Process Logic
--process_logic;
--Test scenario for fail
v_environment_in := 'XX';
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20000, 'Error!');
END t2;
/
show errors
$ cat catch_err.pc
#include <stdio.h>
#include <sqlca.h>
extern void sqlglm( char*, size_t*, size_t* );
extern void sqlgls( char*, size_t*, size_t* );
void exit(int);
void sql_error(msg)
char *msg;
{
size_t clen, fc;
char cbuf[128];
clen = sizeof (cbuf);
sqlgls((char *)cbuf, (size_t *)&clen, (size_t *)&fc);
printf("\n%s\n", msg);
printf("Error Statement obtained using sqlgls is--\n%s\n", cbuf);
sqlglm((char *)cbuf, (size_t *) &clen, (size_t *) &clen);
/*
sqlglm((char *)cbuf, 128 , 128 );
*/
printf("Full Error Message obtained using sqlglm is ========");
printf ("\n%.*s\n", clen, cbuf);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
exit(0);
}
void main()
{
EXEC SQL BEGIN DECLARE SECTION;
char *uid = "ops$xxxxx/xxxxx";
EXEC SQL END DECLARE SECTION;
EXEC SQL WHENEVER SQLERROR do sql_error("Oracle error");
EXEC SQL CONNECT :uid;
EXEC SQL EXECUTE
begin
ops$xxxxx.t2('D');
end;
END-EXEC;
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
exit(1);
}
$
$ ./catch_err
Oracle error
Error Statement obtained using sqlgls is--
begin ops$xxxxx . t2 ( 'D' ) ; end ; À
Full Error Message obtained using sqlglm is ========
ORA-20000: Error!
ORA-06512: at "OPS$xxxxx.T2", line 16
ORA-06512: at line 1
$
*/
--end sample code
Rakesh, January 08, 2011 - 9:56 pm UTC
Dear Sir,
Can you provide your views on the following mentioned above?
"
This gives me the error details of the raise_application_error line and not actual line of error
(v_environment_in := 'XX'; --here).
"
Thanks and keep up the good work.
Rakesh
January 10, 2011 - 7:43 am UTC
put whatever you want into your_error_message.
you were sending:
p_return_msg_inout := DBMS_UTILITY.FORMAT_ERROR_STACK()||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE();
before, use that as your input to raise application error.
Excellent! Opinion requested for running a procedure from UNIX shell script
A reader, January 10, 2011 - 10:25 pm UTC
Dear Sir,
Thanks for the excellent advice.
This gives me the correct error details of the actual line of error (v_environment_in := 'XX'; --here).
/*
--start sample code
--Database version is Oracle 11g R1
--PROCEDURE t2 with raise_application_error
create or replace PROCEDURE t2(
p_environment_in IN VARCHAR2
)
IS
v_environment_in varchar2(1);
v_err_code number;
v_err_message varchar2(4000);
BEGIN
--Process Logic
--process_logic;
--Test scenario for fail
v_environment_in := 'XX';
EXCEPTION
WHEN OTHERS THEN
v_err_code := SQLCODE;
v_err_message := DBMS_UTILITY.FORMAT_ERROR_STACK()||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE();
dbms_output.put_line(chr(10) || '-' || v_err_code || '-' || v_err_message );
raise_application_error(-20000, 'Error! '||v_err_message);
END t2;
/
show errors
--run details of the Pro*C program
$ cd $BE
$ ./catch_err
Oracle error
Error Statement obtained using sqlgls is--
begin ops$xxxxx . t2 ( 'D' ) ; end ; À
Full Error Message obtained using sqlglm is ========
ORA-20000: Error! ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "OPS$xxxxx.T2", line 14
ORA-06512: at "OPS$xxxxx.T2", line 22
ORA-06512: at line 1
$
--Verifying the error details
SQL> l 14
14* v_environment_in := 'XX';
SQL> l 22
22* raise_application_error(-20000, 'Error! '||v_err_message);
SQL>
--end sample code
*/
On similar line in addition to the original question, we need to run the procedure from the UNIX shell script.
Can you please provide your opinion on the following approach to do error handling?
/*
--start sample code
--Database version is Oracle 11g R1
--PROCEDURE t2 with raise_application_error
create or replace PROCEDURE t2(
p_environment_in IN VARCHAR2
)
IS
v_environment_in varchar2(1);
v_err_code number;
v_err_message varchar2(4000);
BEGIN
--Process Logic
--process_logic;
--Test scenario for fail
v_environment_in := 'XX';
EXCEPTION
WHEN OTHERS THEN
v_err_code := SQLCODE;
v_err_message := DBMS_UTILITY.FORMAT_ERROR_STACK()||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE();
dbms_output.put_line( 'STRT');
dbms_output.put_line(SQLCODE);
dbms_output.put_line( 'STRTSTCK');
uxpsubm.p_Log_Errors ( 'Error_Stack...' || Chr(10) || DBMS_UTILITY.FORMAT_ERROR_STACK() );
dbms_output.put_line( 'STRTBTRC');
uxpsubm.p_Log_Errors ( 'Error_Backtrace...' || Chr(10) || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE() );
dbms_output.put_line( 'ENDD');
raise_application_error(-20000, 'Error! '||v_err_message);
END t2;
/
show errors
--UNIX shell script calls a sql program catch_error.sql for running a procedure
$ cat catch_error.sh
#!/bin/ksh
#
if [ ${UIPW:-0} = 0 ];
then
UIPW="/"
fi
a='D'
echo $a
export a
#
# run sqlplus to print the report
#
echo "Starting sql script...."
MSG=`sqlplus -s $UIPW @catch_error.sql $a | col -b |rmnl | sed -n '/STRT/,/ENDD/p'`
echo $?
echo "Completed sql script...."
R_CD=`echo $MSG| awk '{print $2}'`
echo $R_CD
echo $MSG
if [[ $R_CD -ne 0 ]]
then
echo "`date` Failure"
exit 1
else
echo "`date` Success"
fi
exit $?
--SQL program catch_error.sql for running a procedure
$ cat catch_error.sql
--set timing on verify on termout on feedback on timing on
set heading off
whenever sqlerror exit 1
whenever oserror exit 2
set verify off
column a format a10
variable a varchar2(10);
begin
select '&&1' into :a from dual;
end;
/
set serveroutput on size 100000
EXECUTE ops$xxxxx.t2(:a);
pause
exit
$
--run details of the UNIX Shell script program
$ sh catch_error.sh
D
Starting sql script....
0
Completed sql script....
-6502
STRT -6502 STRTSTCK Error_Stack... ORA-06502: PL/SQL: numeric or value error: character string buffer too small STRTBTRC Error_Backtrace... ORA-06512: at "OPS$xxxxx.T2", line 14 ENDD
Mon Jan 10 22:49:33 EST 2011 Failure
--end sample code
*/
Thanks
Rakesh
January 11, 2011 - 5:58 am UTC
that works - using sqlplus like that - however you'd be much much much better off using a scripting language that actually lets you connect to the database and do stuff - perl or whatnot.
dbms_utility.FORMAT_ERROR_BACKTRACE in pro*C instead of in SQL
DVN, April 02, 2013 - 3:38 am UTC
Hi Tom,
We have a common Pro*C module which prints the error based on sqlca.sqlcode value returned from a procedure/package.We have around 5000 oracle packages/procedures in our schema and 1 million lines of PL/SQL code.All DMLs in procedures/packages don't have dbms_utility.FORMAT_ERROR_BACKTRACE or DBMS_UTILITY.FORMAT_ERROR_STACK so many times we had spent long time which query or procedure failed when too many rows/STR bind value/no data found error came etc
Is there an easy way using the pro*C common module or using V$<tables> to get the last error details that gives me which procedure at what line failed.Also it will be very good if it gives me the values that are passed to the procedure/package?
Please let me know your valuable inputs
April 22, 2013 - 1:13 pm UTC
I'm confused - the default error message you get would have the complete call stack in it.
unless someone catches an exception and makes it "non-exceptional".
give me a for example - tiny procedure that fails, tiny proc that runs it and cannot find out where it failed just by recording the error message it gets back?
Example of Scenario Asked for Trace Back
DVN, July 02, 2013 - 7:53 pm UTC
Hi Tom, Thanks for your reply and I just saw it..my problem is like this..we use pro*c so first we call a stored procedure from one Pro*C function and get the data set..we use that data set to get additional data from other transaction related tables and/or to update the other tables.For doing this we again call another set of stored procedure. During this process if we get any error then our application calls a generic function which writes error into the log file but it doesn't have the base data that got using first function to store in some table.
We have more than 100 of Pro*C Servers which use this generic function to print the error in the log and error can come from any of the procedure so what I need is tracing back mechanism which gives me the set of queries that got ran and parameters passed to it so that I can get the required transaction reference along with error in a application log table.
Right now I can write only error but it will not contain transaction reference as it is not supplied to the generic Pro*C error function
Is there a way to get this transaction data that is used?
July 16, 2013 - 12:18 pm UTC
you would have to track that. once you've made the call to the database and it was successful - we lose all of that metadata, we don't care about it - it isn't anything we'd store.
YOU will have to log this level of detail if this is what you want.
Used Global Variables
DVN, November 06, 2013 - 2:53 am UTC
Hi Tom..actually resolved the issue using C Global Variables.Fortunately we have common workflow module and error logging used by all components so was able to use Global Variables and able to capture error into database