plsql propagating/raising exception from a subprogram/unit - plsql

Lets say i am calling a plsql procedure from another procedure (all defined in the same package)
I am trying to raise an application error from proc1 to be displayed on a c# program(proc1 will be the entry call) when something goes wrong. Its straightforwrd when an exception happens within proc1. But how to propagate the same error that gets raised in proc2?
Do i have to declare the same user_exception EXCEPTION in proc1 as well? Or
should i have a global exception variable at the package level ? Whats the standard practice?
(pls ignore any code errors such an exception_init etc..) I had only included the code for the concept..
create or replace procedure proc1 is
begin
--some plsqlcode
proc2();
exception
raise_application_error( ???? );
end proc1;
create or replace procedure proc2 is
user_exception EXCEPTION;
begin
--do something
if (somefalse condition) then
raise user_exception
exception
when user_exception then
--do some error handling
raise;
end proc2;
I hope i was clear in framing the question. Thanks in advance for suggestions/tips.

If you have a package, standard practice is to declare exception in a package.
create or replace package pkg is
user_exception exception;
procedure proc1;
procedure proc2;
end pkg;
create or replace package body pkg is
procedure proc1 is
begin
proc2;
exception
when user_exception then
raise;
end;
procedure proc2 is
begin
raise user_exception;
end;
end pkg;

One solution is to declare the exception so it's visible in both procedures:
user_exception EXCEPTION;
create or replace procedure proc1 is
begin
--some plsqlcode
proc2();
exception
when user_exception then -- added
raise_application_error( ???? ); -- added
when others then
raise_application_error( ???? );
end proc1;
create or replace procedure proc2 is
begin
--do something
if (somefalse condition) then
raise user_exception
exception
when user_exception then
--do some error handling
raise;
end proc2;
Share and enjoy.

Related

Terminate script immediately

im new with PL_SQL, i want to ask a question. A need to terminate this script when reaches te exit condition, but its failing, it continues. Im not able to terminate the execution of the script when WHENEVER SQLERROR EXIT SQL.SQLCODE is reached. Any suggestions??
WHILE V_COUNT_MENSAJES>0
LOOP
DELETE
FROM TB_ICP_ENVIOMENSAJES
WHERE KEY_MENSAJE = P_KEY_MENSAJE;
WHENEVER SQLERROR EXIT SQL.SQLCODE;
END LOOP;
END;
WHEN others THEN
dbms_output.put_line('Error en la consulta!');
END;
-----REST OF CODE
Try to incorporate the below snippet it will help to terminate the
code whenever you reach any exception. Hope this helps.
DECLARE
p_err_cd PLS_INTEGER;
p_err_msg VARCHAR2(32767 CHAR);
V_COUNT_MENSAJES PLS_INTEGER;
P_KEY_MENSAJE VARCHAR2(1000 CHAR);
BEGIN
WHILE V_COUNT_MENSAJES > 0
LOOP
BEGIN
DELETE FROM TB_ICP_ENVIOMENSAJES WHERE KEY_MENSAJE = P_KEY_MENSAJE;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,SQLERRM,TRUE);
END;
END LOOP;
END;
You don't have to use "WHENEVER SQLERROR EXIT SQL.SQLCODE;" code inside PLSQL block.Whenever error occur control will pass to exception.Please see the below example for the same.
DECLARE
V_COUNT_MENSAJES NUMBER:=10;
ERROR_1 EXCEPTION;
BEGIN
WHILE V_COUNT_MENSAJES>0
LOOP
RAISE ERROR_1;
END LOOP;
EXCEPTION
WHEN others THEN
dbms_output.put_line('Error en la consulta!');
END;
/
Also please note when you’re executing a script, there are many cases in which you want an error to cause SQL*Plus to terminate where we use the following command and not inside plsql block:
SQL> WHENEVER SQLERROR EXIT SQL.SQLCODE

How to remove extra information form error message after executing a package body?

I want to remove extra information form error message after executing a package body.
Example:
If I run a anonymous block then the error message come like -
ERROR at line 1:
ORA-20010: Object ID PE556092 is not Produced by the Template TP000036
ORA-06512: at "EXAMPLE.TESTPROC", line 5
ORA-06512: at line 1
But i want to show only the below error message:
ORA-20010: Object ID PE556092 is not Produced by the Template TP000036
You can use the below to get the Error Code and Message respectively:
dbms_output.put_line('Error code: '||sqlcode);
dbms_output.put_line('Error msg: '||sqlerrm);
Read more about SQLERRM.
You can do that by defining an exception and mapping it to the SQLCODE of the raised error. Then you handle the logic in the exception handler.
Example, here I map to error -20010 (the one you are using):
declare
err_obj_not_produced exception;
pragma exception_init (err_obj_not_produced, -20010);
l_object varchar2 (50);
l_template varchar2 (50);
begin
run_your_code ('With values');
exception
when err_obj_not_produced then
return 'Object ID ' || l_object || ' is not Produced by the Template ' || l_template;
end;
Another one way to hide information about previous errors. Suppose you have two procedures:
create or replace procedure proc1 is
begin
raise no_data_found;
end;
/
create or replace procedure proc2 is
begin
proc1;
exception
when no_data_found then
raise_application_error(-20010, 'There is no spoon, Neo.');
end;
/
when you run a block in SQL*Plus, you get:
SQL> begin
proc2;
end;
/
begin
*
ERROR at line 1:
ORA-20010: There is no spoon, Neo.
ORA-06512: at "DEV.PROC2", line 6
ORA-06512: at line 2
You can change proc2 like this:
create or replace procedure proc2 is
begin
proc1;
end;
/
And call it like this with desired result:
SQL> begin
begin
proc2;
exception
when no_data_found then
raise_application_error(-20010, 'There is no spoon, Neo.', false);
end;
exception
when others then
dbms_output.put_line(SQLERRM);
end;
/
ORA-20010: There is no spoon, Neo.
PL/SQL procedure successfully completed.
This example shows how third parameter of raise_application_error procedure works. If you pass false, procedure deletes information about previously raised exceptions from error stack. It also will be impossible to get this information using dbms_utility.format_error_backtrace.
As Jon Heller noticed in comments, hiding information about exceptions is a bad practice (and using when others then without raise too, as Jeffry Kemp noticed), so, I hope you know what you are doing. This way or another, it is a shooting yourself in the foot.

Anonymous PL/SQL block checked exception

I'm trying to catch an exception within my anonymous PL/SQL block
DECLARE
...
BEGIN
FOR herstell_row IN (
...
)
LOOP
...
DECLARE
table_does_not_exists exception;
pragma exception_init( table_does_not_exists, -942 );
BEGIN
INSERT INTO SMART_MONITORING_MACHINE_NAV_B (
MACHINE,
NAVIGATION_LEVEL_ID
)
SELECT
old_binding.MACHINE,
pv_id
FROM
SMART_MACHINE_NAV_BINDING old_binding
WHERE
old_binding.NAVIGATION_LEVEL_ID = herstell_row.HENAME1;
EXCEPTION
WHEN table_does_not_exists THEN null;
END;
END LOOP;
END;
I know the table SMART_MACHINE_NAV_BINDING doesn't exist in my case, so I need the nested anonymous block to ignore its code. But I always get this error:
Error report -
ORA-06550: line 41, column 14:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 33, column 10:
PL/SQL: SQL Statement ignored
You can't compile code with non-existent table, but you can try to execute it using EXECUTE EMMEDIATE:
DECLARE
...
BEGIN
FOR herstell_row IN (
...
)
LOOP
...
DECLARE
table_does_not_exists exception;
pragma exception_init( table_does_not_exists, -942 );
BEGIN
execute immediate
'INSERT INTO SMART_MONITORING_MACHINE_NAV_B (
MACHINE,
NAVIGATION_LEVEL_ID
)
SELECT
old_binding.MACHINE,
pv_id
FROM
SMART_MACHINE_NAV_BINDING old_binding
WHERE
old_binding.NAVIGATION_LEVEL_ID = :P' using herstell_row.HENAME1;
EXCEPTION
WHEN table_does_not_exists THEN null;
END;
END LOOP;
END;
Also you don't need exceptions here, you can check existence of a table using system view:
declare
table_created number;
begin
select count(*)
into table_created
from all_tables
where table_name = ...
and owner = ...;
if table_created > 0 then
execute immediate 'insert into ...';
end if;
end;
More information about EXECUTE IMMEDIATE statement: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/executeimmediate_statement.htm#LNPLS01317
Oracle does not know this error table_does_not_exists it is user defined, so you should handle in when others then, for eg.
Exception
When Others then
null;
-- or at this time you can raise your error table_does_not_exists
raise table_does_not_exists;
-- and handle it in another parent block
end;
Exception
when table_does_not_exists then
null;
end;

Exception handling - plsql

I have a problem. Am doing an insert function
case f1.RFD_CATEGORY_CODE when'O1' then 'C1GBC'
when 'O2' then 'C2GBC' else null end
the field is mandatory and thus instead of null i need to show an error message if the code is not taking C1GBC or C2GBC. and if the code is taking C1GBC or C2GBC then show successful as message.
i have create an exception below but am getting error
create or replace procedure CTP_CODE as
declare
--RFD_CAT_ERR varchar2;
RFD_CAT_ERR EXCEPTION;
begin
if RFD_CATEGORY_CODE is '01' then RFD_CATEGORY_CODE is 'C1GBC';
DBMS_OUTPUT.PUT_LINE ('No1. Successful Operation');
else
if RFD_CATEGORY_CODE is '02' then RFD_CATEGORY_CODE is 'C2GBC';
DBMS_OUTPUT.PUT_LINE ('No2. Successful Operation');
end if;
raise RFD_CAT_ERR;
end if;
EXCEPTION
when RFD_CAT_ERR then
DBMS_OUTPUT.PUT_LINE ('Error message!');
end;
/
Wrong Code also wrong syntax..
Whenever your code goes in else condition it will throw error as after executing 2nd if it will go to "raise RFD_CAT_ERR;" part and raise an exception.
so u should handle error in elsif after 2nd If condition.
You say the field is mandatory. If by that you mean the field in the table is constrained as not null then you don't have to worry about raising an exception. The insert statement will do that for you. All you have to do is catch it in your exception handler and use RAISE_APPLICATION_ERROR to return a meaningful message.
Do that rather than try to print an error message. If your procedure is called by a batch process, there will be no one there to see it.
This works for me :D
CASE f1.RFD_CATEGORY_CODE
WHEN 'O1' THEN 'C1GBC'
WHEN 'O2' THEN 'C2GBC'
ELSE 'error'
Then raise any errors for exception

Catching a constraint violation in psql

I am using sql developer, and have added a constraint to one of my tables.
constraint valid_gender check(gender in ('M','F','I','T'))
When I try to add an entry with say 'x' for gender using a plsql procedure, it fails with constraint violation (as it should).
I want to add a "Catch" to the plsql procedure so that if valid_gender is voilated I can raise_application_error specific to it. Is this possible?
Oracle will raise an exception that says:
ORA-02290: check constraint (yourschema.valid_gender) violated
You can catch that in an exception handler and raise your own exception instead using raise_application_error in a couple of ways.
1) You can specifically trap the ORA-02290 exception like this:
declare
e_check_violated exception
pragma exception_init (e_check_violated, -2290);
begin
insert ...
exception
when e_check_violated then
if sqlerrm like '%(yourschema.valid_gender)%' then
raise_application_error(-20001,'Invalid gender');
else
raise;
end if;
end;
2) You can trap all exceptions and inspect them:
begin
insert ...
exception
when others then
if sqlerrm like 'ORA-02290:%(yourschema.valid_gender)%' then
raise_application_error(-20001,'Invalid gender');
else
raise;
end if;
end;
In a large application it is quite common to have an exception handling procedure to generalise this and look up the constraint-specific message in a table.
use anonym block in your code...
BEGIN
INSERT or update...
EXCEPTION
WHEN dup_val_on_index THEN
RISE...
END;
You could just test it first:
if gender_value not in ('M','F','I','T') then
raise_application_error...
end if;

Resources