In my application oracle procedure is currently called through unix script, when there is error in exception block we are handling something like this :-
PROC_LOGS('<PROC_NAME>', <TABLE_NAME>, 'Exception','Exception occured - '||SQLERRM);
PROC_LOG does nothing but inserts entry into log table but we need now to catch that error in unix also (return some value except 0) from where is it called so remaining process can be terminated best on that, what is the best way to do this?
CREATE OR REPLACE....
...
DECLARE
....
BEGIN
..
...
EXCEPTION
WHEN OTHERS THEN
PROC_LOGS('<PROC_NAME>', <TABLE_NAME>, 'EXCEPTION','EXCEPTION OCCURED - '||SQLERRM);
END;
Unix script part from where I m calling procedure
sqlplus <<-!
$US/$P#$I
set serveroutput on
#$SQL/execute_proc.sql $1 $2
execue_proc contains something like this :-
define IN_1 = '&1';
define IN_2 = '&2';
spool $SQL/test_&&IN
declare
P_IN_TABLE_NAME varchar2(250) := '&&IN_TABLE_NAME';
P_IN_REGION varchar2(250) := '&&IN_REGION';
begin
PROC_UPDATE_CHARGE_FACT(P_IN_TABLE_NAME,P_IN_REGION);
end;
/
spool off
You need to raise the exception, like this:
EXCEPTION
WHEN OTHERS THEN
PROC_LOGS('<PROC_NAME>', <TABLE_NAME>, 'EXCEPTION','EXCEPTION OCCURED - '||SQLERRM);
RAISE;
END;
or use RAISE_APPLICATION_ERROR:
EXCEPTION
WHEN OTHERS THEN
PROC_LOGS('<PROC_NAME>', <TABLE_NAME>, 'EXCEPTION','EXCEPTION OCCURED - '||SQLERRM);
RAISE_APPLICATION_ERROR (-20002, 'An unexpected exception occurred.');
END;
You are presumably calling SQL*Plus, and SQL*Plus has a configuration item that should help.
http://docs.oracle.com/cd/E11882_01/server.112/e16604/ch_twelve052.htm#BACHCFEF
Since you probably execute the procedure from an anonymous block, the error should propagate to SQL*Plus and "WHENEVER SQLERROR EXIT SQL.SQLCODE" will return the relevant error code to the unix environment.
One way could be to have proc_log() to also write to a log file and then have the unix script to check the log file.
Related
As in Java there is finally block which executed in all conditions.
Is there any similar function in Oracle PL/SQL which will be executed whenever procedure completes its execution even a return statement is used?
There is no equivalent of FINALLY but you can simulate it using nested PL/SQL blocks;
DECLARE
-- Your variables.
return_early BOOLEAN := FALSE;
BEGIN
-- Do something
DECLARE
-- Local variables in "try" block
BEGIN
-- Equivalent of "try" block
-- Do something that may raise an exception
IF some_condition THEN
return_early := TRUE;
-- you could also use "GOTO end_try;" rather than surrounding the
-- following statements in an "ELSE" statement
ELSE
-- Do something else that may raise an exception
END IF;
EXCEPTION
WHEN your_exception THEN
-- Equivalent of "catch" block
END;
<<end_try>>
-- Handle "finally" here, after end of nested block.
-- Note: you can only see variables declared in this outer block
-- not variables local to the nested PL/SQL block.
IF return_early THEN
RETURN;
END IF;
-- Continue and do more stuff.
END;
/
Another thread on Stackoverflow can help out here : Exception handling in pl/sql
Where Tony says :
"You can created nested blocks:"
create or replace procedure Trial
is
Begin
begin
---Block A--
EXCEPTION
when others then
insert into error_log values('error');
end;
begin
--Block B ----
end;
end;
The solutions provided in other answers does not implement exact try-catch-finally logic. E.g. the finally should be executed even if exception is reraised and even if in did not handled at all. In other words, the finally block must be called always.
The most similar behavior to Java's finally is the following. Unfortunately, here we have to wrap finally block into a procedure. We have no choice in PL/SQL.
declare
begin
declare
EXPECTED_EXCEPTION_RECOVERABLE exception;
EXPECTED_EXCEPTION_FATAL exception;
EXPECTED_EXCEPTION_UNHANDLED exception;
procedure finally is
begin
dbms_output.put_line('FINALLY section executed');
end;
begin
dbms_output.put_line('Trying dangerous section...');
/* uncomment to try different behavior */
--raise EXPECTED_EXCEPTION_RECOVERABLE;
--raise EXPECTED_EXCEPTION_FATAL;
--raise EXPECTED_EXCEPTION_UNHANDLED;
dbms_output.put_line('Dangerous section is executed successfully');
FINALLY();
exception
when EXPECTED_EXCEPTION_RECOVERABLE then
dbms_output.put_line('Recoverable exception handled.');
FINALLY();
when EXPECTED_EXCEPTION_FATAL then
dbms_output.put_line('Fatal exception handled and will be reraised');
FINALLY();
RAISE;
when OTHERS then
dbms_output.put_line('Unhandled exception is just reraised after finally section');
FINALLY();
RAISE;
end;
end;
/
It seems, this solution looks enough readable;
You can create a custom Exception and then Raise it at the end of your other exceptions, this custom exception must be on an outside block:
BEGIN
BEGIN
--DO SOME CODE HERE
EXCEPTION
WHEN NO_DATA_FOUND THEN
--HANDLE EXCEPTION
RAISE CUSTOM_EXCEPTION;
END;
EXCEPTION
WHEN CUSTOM_EXCEPTION THEN
--HANDLE THE FINALLY CODE HERE
END;
I'm trying to get the full error message from oracle.
For example - I have a very long procedure that doing a lot of manipulation on
a lot of objects, and in my log I got the error
object no longer exist.
And this is my insert to the log (even it is a generally question - not specific to this example):
EXCEPTION WHEN OTHERS THEN
v_errno := sqlcode;
V_ERRMSG := SQLERRM;
INSERT INTO ERR_TABLE (ERROR_NUMBER, ERROR_MESSAGE,PROGRAM#)
VALUES (V_ERRNO, V_ERRMSG,'MY_PKG');
COMMIT;
The problem is that I don't know which table it talking about - because this
information doesn't exsits.
Is there a way to get it?
I guess that oracle save it in some place.
thanks!
For internal logging (not only for errors) I use a procedure like this:
PROCEDURE Put(
LogMessage IN T_LOG_ENTRIES.LOG_MESSAGE%TYPE,
ErrCode IN T_LOG_ENTRIES.LOG_ERROR_CODE%TYPE DEFAULT 0) IS
ErrorStack T_LOG_ENTRIES.LOG_ERROR_STACK%TYPE;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF ErrCode <> 0 THEN
ErrorStack := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE();
ErrorStack := SQLERRM(ErrCode) || CHR(13) || ErrorStack;
END IF;
INSERT INTO T_LOG_ENTRIES
(LOG_DATE, LOG_MESSAGE, LOG_ERROR_CODE, LOG_ERROR_STACK)
VALUES
(CURRENT_TIMESTAMP, LogMessage, ErrCode, ErrorStack);
COMMIT;
END Put;
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE() provides the full error stack. You should use AUTONOMOUS_TRANSACTION since transactions are rolled back in case of exception, i.e. your log message would be deleted also.
Then you can use the procedure for example as this:
BEGIN
...
EXCEPTION WHEN OTHERS THEN
Put('Error in my procedure', sqlcode);
END;
I am trying to return list of number from a stored procedure. My stored procedure gets stopped in for loop when exception occur. I have added exception clause and control is going inside the exception clause to continue the loop but still no luck.
How to continue the loop when exception occur? Thanks.
CREATE OR REPLACE PROCEDURE getNumber(l_list IN CUSTOMLIST, l_output OUT NUMLIST)
IS
n_num varchar2(5);
BEGIN
l_output := NUMLIST();
FOR i IN l_list.FIRST .. l_list.LAST LOOP
l_output.EXTEND(l_list.LAST);
BEGIN
SELECT NUM into n_num
FROM sometable WHERE some condition;
l_output(i) := n_num;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('TRUE');
CONTINUE;
END;
END LOOP;
END;
Maybe you should handle other exceptions too.
Try with adding
WHEN OTHERS THEN
[statements]
The code I posted in question is working when I restart the SQL developer. Something was wrong at SQL developer level when I copy paste the EXCEPTION clause. But when I type the EXCEPTION clause it's started showing be no_data_found option and that one I selected and it worked.
If i have an oracle pl/sql procedure, I define an exception block like this:
exception
WHEN OTHERS THEN
errMsg := substr(SQLERRM, 1, 100);
dbms_output.put_line ('--> Error ALIAS1: ' || errMsg);
end;
Will this be executed no matter what kind of exception is raised?
WHEN OTHERS is a catch-all for any PL/SQL exception that isn't handled explicitly by its own WHEN clause.
It isn't normally a good idea to use it, for that reason; it's easy to accidentally trap and lose an important message about something bad happening. You should catch and handle the specific exceptions you expect to encounter. If you do want to record or log any other exceptions you should include a RAISE in the exception handler so everything else gets propagated normally.
...
exception
when others then
errMsg := substr(SQLERRM, 1, 100);
dbms_output.put_line ('--> Error ALIAS1: ' || errMsg);
raise;
end;
Read more about exceptions generally here, and about OTHERS here.
I have a few SQL (Select/Update/Insert) syntax that I will run inside PL/SQL one after another
is there any way to check if each syntax completed correctly and if there is some error it will not halt the whole PL/SQL, it will just return "OK" or "Not OK" to a variable so I can use it with IF?
UPDATE
I came up with this function, but it dose not seems to work, it returns 0 all time!
create or replace
FUNCTION EXECUTE_SQL(
V_SQL IN VARCHAR2 )
RETURN NUMBER
AS
V_RESULTS NUMBER := 1;
BEGIN
BEGIN
EXECUTE IMMEDIATE V_SQL;
EXCEPTION
WHEN OTHERS THEN
-- the following line is just for debugging!
dbms_output.put_line(SQLERRM);
V_RESULTS:= 0;
END;
RETURN V_RESULTS;
END EXECUTE_SQL;
what is wrong wit it (if any)!
cheers
if sql%rowcount > 0 then
-- insert or update statement affected sql%rowcount rows
end if;
As for the correct syntax: if the syntax is wrong, it won't even compile. If there's a data consistency error (such as divide by 0 error, or primary key violation) an exception will be thrown. Such exception can be caught in exception handlers
In the exception handler, you can then check sqlerrm for more details:
begin
update t set x = ...
exception when others then
dbms_output.put_line(SQLERRM);
end;
There are also a few predefined exceptions that you can check on:
begin
update t set x = ...
exception
when DUP_VAL_ON_INDEX
-- primary key or unique key violation
when OTHERS
-- other kind of exception
end;
If the syntax is not correct the entire block will be invalid, so you'll not be able to run it.
If you want to run all statements, despite that one can raise an exception, you can:
BEGIN
BEGIN
statement1;
EXCEPTION
when exception1 then
some commands or null;
when exception2 then
some commands or null;
END;
BEGIN
statement2;
EXCEPTION
when exception3 then
some commands or null;
when exception4 then
some commands or null;
END;
etc.
END;
Write show errors
begin
update t set x = ...
exception
when DUP_VAL_ON_INDEX
-- primary key or unique key violation
when OTHERS
-- other kind of exception
end;
/
show errors
It will show errors if any.