Calling user defined exception but instead when others than exception is raising - oracle

I have a anonymous block like below
DECLARE
exc1 EXCEPTION;
i integer:='1';
BEGIN
BEGIN
IF i = 1 THEN
RAISE exc1;
END IF;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20481,
'Error while inserting/update into Table- ' ||
SQLERRM);
END;
EXCEPTION
WHEN exc1 THEN
raise_application_error(-20001, 'test123');
END;
I just want to raise the exc1 exception. But here instead when others then exception is raising. I specifically raise the exception exc1 in if condition block so it has to call right?

The best option here is to have just one exception block:
DECLARE
exc1 EXCEPTION;
i integer:='1';
BEGIN
IF i = 1 THEN
RAISE exc1;
END IF;
EXCEPTION
WHEN exc1 THEN
raise_application_error(-20001, 'test123');
WHEN OTHERS THEN
raise_application_error(-20481,
'Error while inserting/update into Table- ' ||
SQLERRM);
END;
/
But if you really need nested anonymous block with own exceptions blocks, you need to add one more exception handler:
DECLARE
exc1 EXCEPTION;
i integer:='1';
BEGIN
BEGIN
IF i = 1 THEN
RAISE exc1;
END IF;
EXCEPTION
WHEN exc1 THEN
raise;
WHEN OTHERS THEN
raise_application_error(-20481,
'Error while inserting/update into Table- ' ||
SQLERRM);
END;
EXCEPTION
WHEN exc1 THEN
raise_application_error(-20001, 'test123');
END;
/
PS. I'd suggest you do not use when others then without adding original exception into the error stack, ie 3rd parameter of raise_application_error() should be true:
DECLARE
exc1 EXCEPTION;
i integer:='1';
BEGIN
IF i = 1 THEN
RAISE exc1;
END IF;
EXCEPTION
WHEN exc1 THEN
raise_application_error(-20001, 'test123', true);
WHEN OTHERS THEN
raise_application_error(-20481,
'Error while inserting/update into Table- ' ||
SQLERRM
, true);
END;
/

Related

Set Variable value

I have declared the variable for v_error but when inside my begin I do set a number value for the variable I get a error under the equals 'Syntax Error'
Code Below:
DECLARE
v_error varchar(1);
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE :v_tab1';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -942 THEN
set #v_error = 0; — error here
DBMS_OUTPUT.put_line('This table does not exist!');
ELSE
RAISE;
DBMS_OUTPUT.put_line('Exception Occurred on table drop' );
v_error := '1';
END IF;
END;
Keeping aside the usage of :v_tab1, which strongly depends on the client/tool you use to run this code, you need to edit your syntax according to what you already do a few lines after:
DECLARE
v_error varchar(1);
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE :v_tab1';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -942 THEN
v_error := '0'; /* <------ like you do for v_error := '1'; */
DBMS_OUTPUT.put_line('This table does not exist!');
ELSE
RAISE;
DBMS_OUTPUT.put_line('Exception Occurred on table drop' );
v_error := '1';
END IF;
END;

PL/SQL Continue exection after error handled

I'm newbie with PL/SQL and i've got the following situation.
In the following scritp i want that the script continue iterating if they found any exception. The exception are handled but I cannot execute the continue statement out of a loop.
declare
l_max_ID number;
l_Temp_val number;
type array_t is varray(135) of varchar2(30);
arrayTable array_t := array_t('YSXQTAAA', 'YSXQTAFA', ... );
array array_t := array_t('YSXQNAAA', 'YSXQNAFA', ...);
begin
dbms_output.put_line(arrayTable.count);
for i in 1..arrayTable.count loop
dbms_output.put_line('Tabla impactada ' || arrayTable(i));
execute immediate 'select max(id)+1 from ' || arrayTable(i) into l_max_ID;
execute immediate 'alter sequence ' || array(i) || ' restart start with ' || TO_CHAR(l_Max_ID);
dbms_output.put_line('alter sequence RS1.' || array(i) || ' restart start with ' || TO_CHAR(l_Max_ID));
end loop;
rollback;
EXCEPTION
WHEN NO_DATA_FOUND THEN
/* HAndle an error that gets raised when a query returns nothing */
dbms_output.put_line('Error 1');
WHEN TOO_MANY_ROWS THEN
/* HAndle the situation when too much data is returned such as with a select-into */
dbms_output.put_line('Error 2');
WHEN OTHERS THEN
dbms_output.put_line('Error 3');
end;
The problem is that some tables doesn't have id column and the select throw an exception. The array contains more than a hundred elements and delete each one takes a lot of time.
Put the exception handling block inside the loop:
begin
dbms_output.put_line(arrayTable.count);
for i in 1..arrayTable.count loop
begin
dbms_output.put_line('Tabla impactada ' || arrayTable(i));
execute immediate 'select max(id)+1 from ' || arrayTable(i) into l_max_ID;
execute immediate 'alter sequence ' || array(i) || ' restart start with ' || TO_CHAR(l_Max_ID);
dbms_output.put_line('alter sequence RS1.' || array(i) || ' restart start with ' || TO_CHAR(l_Max_ID));
EXCEPTION
WHEN NO_DATA_FOUND THEN
/* HAndle an error that gets raised when a query returns nothing */
dbms_output.put_line('Error 1');
continue;
WHEN TOO_MANY_ROWS THEN
/* HAndle the situation when too much data is returned such as with a select-into */
dbms_output.put_line('Error 2');
continue;
WHEN OTHERS THEN
dbms_output.put_line('Error 3');
continue;
end;
end loop;
rollback;
end;

PLSQL - exception in a procedure

Use exception in a procedure.
Procedure for insert into statement.
CREATE OR REPLACE PROCEDURE pSaveProductGroup (p_parentCode VARCHAR2, p_nameGroup VARCHAR2) IS
v_var "ProductGroups"."code"%type;
BEGIN
select p."code" into v_var
from "ProductGroups" p
where p."code"=p_parentCode;
if v_var is not null then
INSERT INTO "ProductGroups"
("parentCode","nameGroup")
VALUES(p_parentCode,p_nameGroup);
end if;
EXCEPTION
WHEN v_var is null then
dbms_output.put_line('Undefined group.');
END;
It should print exception when needed.
Error: Error(18,12): PLS-00103: Encountered the symbol "IS" when expecting one of the following: . then or
You can do something like this to catch the exception.
CREATE OR REPLACE PROCEDURE pSaveProductGroup (p_parentCode VARCHAR2,
p_nameGroup VARCHAR2)
IS
v_var "ProductGroups"."code"%TYPE;
myex EXCEPTION;
PRAGMA EXCEPTION_INIT (myex, -20016);
BEGIN
SELECT p."code"
INTO v_var
FROM "ProductGroups" p
WHERE p."code" = p_parentCode;
IF v_var IS NOT NULL
THEN
INSERT INTO "ProductGroups" ("parentCode", "nameGroup")
VALUES (p_parentCode, p_nameGroup);
ELSE
IF (v_var IS NULL)
THEN
RAISE myex;
END IF;
END IF;
EXCEPTION
WHEN myex
THEN
DBMS_OUTPUT.put_line (
'ERROR_STACK: "Undefined group --> ' || DBMS_UTILITY.format_error_stack);
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (
'ERROR_STACK: NO_DATA_FOUND --> ' || DBMS_UTILITY.format_error_stack);
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
'ERROR_STACK: OTHERS --> ' || DBMS_UTILITY.format_error_stack);
END;
The modified version of the procedure
CREATE OR REPLACE PROCEDURE pSaveProductGroup (p_parentCode VARCHAR2,
p_nameGroup VARCHAR2)
IS
v_var "ProductGroups"."code"%TYPE;
myex EXCEPTION;
PRAGMA EXCEPTION_INIT (myex, -20016);
BEGIN
SELECT p."code"
INTO v_var
FROM "ProductGroups" p
WHERE p."code" = p_parentCode;
IF v_var IS NOT NULL
THEN
INSERT INTO "ProductGroups" ("parentCode", "nameGroup")
VALUES (p_parentCode, p_nameGroup);
ELSE
RAISE myex;
END IF;
EXCEPTION
WHEN myex
THEN
DBMS_OUTPUT.put_line (
'ERROR_STACK: Undefined group --> ' || DBMS_UTILITY.format_error_stack);
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (
'ERROR_STACK: NO_DATA_FOUND --> ' || DBMS_UTILITY.format_error_stack);
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
'ERROR_STACK: OTHERS --> ' || DBMS_UTILITY.format_error_stack);
END;

How to retrieve output parameter from stored procedure in oracle

I have below stored procedure. It works fine. But I wanted to test it for error scenarios. Even when there is an error, the procedure executes successfully without showing the error message. When I enable the set serveroutput on, it shows the error message. But I want to capture the error message.
create or replace PROCEDURE COMP_JSON (
OUT_MESSAGE OUT VARCHAR2,
PNI_ID IN NUMBER
)
AS
CURSOR C1 IS SELECT 1 AS ID,TYPE_ID, COMP, TYPE, PREV_AMOUNT, CURR_AMOUNT FROM V_COMP_COST;
SECID VARCHAR2(100);
K NUMBER:= 0;
L NUMBER:= 1000;--Commit Interval
LRETVALUE VARCHAR2(200):='0';
V_TYPE_ID JSON_DATA.TYPE_ID%TYPE;
V_COMP JSON_DATA.COMP%TYPE;
V_TYPE JSON_DATA.TYPE%TYPE;
BEGIN
APEX_JSON.INITIALIZE_CLOB_OUTPUT;
/* Cost Comparison */
IF NVL(PNI_ID, 1) = 1
THEN
K := 0;
BEGIN
FOR I IN C1
LOOP
V_TYPE_ID := I.TYPE_ID;
V_COMP := I.COMP;
V_TYPE := I.TYPE;
APEX_JSON.OPEN_OBJECT;
APEX_JSON.WRITE('prevAmt',I.PREV_AMOUNT);
APEX_JSON.WRITE('currAmt',I.CURR_AMOUNT);
APEX_JSON.CLOSE_OBJECT;
INSERT INTO JSON_DATA
VALUES (I.ID,I.TYPE_ID,I.COMP,I.TYPE,APEX_JSON.GET_CLOB_OUTPUT);
/* Commit Interval */
K := K+1;
IF MOD(K,L) = 0
THEN
COMMIT;
END IF;
APEX_JSON.FREE_OUTPUT;
IF K > 5
THEN
RAISE_APPLICATION_ERROR(-20000, NULL);
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS
THEN LRETVALUE := '-1,k:Problem in loading Data -' || SQLERRM || ' AT: [' || V_TYPE_ID || '] [' || V_COMP || '] [' || V_TYPE || ']';
END;
COMMIT;
IF LRETVALUE <> '0'
THEN
OUT_MESSAGE := LRETVALUE;
RETURN;
END IF;
END IF;
EXCEPTION
WHEN OTHERS
THEN DBMS_OUTPUT.PUT_LINE('ERROR MESSAGE' || SQLERRM);
END COMP_JSON;
You're using a nested block to throw your exception, but it will continue processing. The outbound variable "OUT_MESSAGE" should capture that value. Is it? if so, you can see what it is with this:
SQL> VAR ERR_MSG VARCHAR2;
SQL> EXEC COMP_JSON(:ERR_MSG, 5); --whatever you use for PNI_ID....
PL/SQL procedure successfully completed.
SQL> PRINT ERR_MSG;
If your program never throws an error, then OUT_MESSAGE will never be set, thus it will be null upon completion of the program.
If you are looking to throw an error from your program if your "nested block" throws an error, then you need to re-raise the exception so that the outer exception catches it:
IF K > 5
THEN
RAISE_APPLICATION_ERROR(-20000, NULL);
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
LRETVALUE := '-1,k:Problem in loading Data -' || SQLERRM || ' AT: [' || V_TYPE_`ID || '] [' || V_COMP || '] [' || V_TYPE || ']';
RAISE_APPLICATION_ERROR(-20000, LRETVALUE );
END;
If you need the caller to raise an exception, you need that your procedure propagates it to the external.
For example:
SQL> create or replace procedure raiseException(p in number) is
2 n number;
3 begin
4 n := p/0;
5 exception
6 when others then
7 dbms_output.put_line('Error message: ' || sqlerrm);
8 raise;
9 end;
10 /
Procedure created.
SQL> create or replace procedure procedureCall is
2 begin
3 raiseException(10);
4 end;
5 /
Procedure created.
The first procedure will print a message and raise an exception; in this way, we have the error message in output and an exception:
SQL> exec procedureCall
Error message: ORA-01476: divisor is equal to zero
BEGIN procedureCall; END;
*
ERROR at line 1:
ORA-01476: divisor is equal to zero
ORA-06512: at "ALEK.RAISEEXCEPTION", line 8
ORA-06512: at "ALEK.PROCEDURECALL", line 3
ORA-06512: at line 1
If you remove the RAISE, the exception will be handled and not propagated, thus giving no error:
SQL> create or replace procedure raiseException(p in number) is
2 n number;
3 begin
4 n := p/0;
5 exception
6 when others then
7 dbms_output.put_line('Error message: ' || sqlerrm);
8 end;
9 /
Procedure created.
SQL> exec procedureCall
Error message: ORA-01476: divisor is equal to zero
PL/SQL procedure successfully completed.

Finding exception (PL/SQL)

I am running a code in Oracle that asks the user to input a route type, and then the program fetches the longest and shortest routes depending on the user-input route, as well as the number of rows fetched. I need to add any exception to the code and I am trying to think of what kind of exception I could add in this case. I was thinking of adding an exception that gives an error if the rows fetched is <1. However, I am not sure if such exception exists. I also need to add an exception for an invalid route type. I have represented this as an IF statement. Not sure if this counts as an exception.
My code is:
SET SERVEROUTPUT ON;
SET VERIFY OFF
DECLARE
v_type VARCHAR2 (20);
min_length NUMBER;
max_length NUMBER;
v_count NUMBER;
BEGIN
v_type := '&InsertTypeRoute';
IF v_type = 'Multi-Lane Divided' OR
v_type = 'Paved Divided' OR
v_type = 'Paved Undivided' THEN
SELECT MIN(LENGTH_KM), MAX(LENGTH_KM), COUNT(LENGTH_KM) INTO min_length, max_length, v_count
FROM TBLROUTE WHERE TYPE = v_type;
DBMS_OUTPUT.PUT_LINE('The minimum length is: ' || TO_CHAR(min_length));
DBMS_OUTPUT.PUT_LINE('The maximum length is: ' || TO_CHAR(max_length));
DBMS_OUTPUT.PUT_LINE ('Total number of '|| v_type ||' route is: ' || TO_CHAR(v_count));
ELSE
DBMS_OUTPUT.PUT_LINE ('Route type cannot be found');
END IF;
/*
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Route type cannot be found'); */
END;
/
How about these exception? Are they appropriate in this case?
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Data not found');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('This program encountered an error');
It is suggested to add SQLCODE and SQLERRM if you are using WHEN_OTHERS along with RAISE
This will tell you exactly what went wrong.
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR MESSAGE :' || SQLCODE || ' :' || SQLERRM );
RAISE;
"Are they appropriate in this case?"
Handling exceptions like this is universally accepted as bad practice. It swallows the real exception, so the user knows that something failed but they have absolutely no idea what.
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('This program encountered an error');
Here is a circumstance where doing nothing is better than doing that.
In your situation I suggest you rely on the default PL/SQL NO_DATA_FOUND exception to handle no records, and raise a bespoke exception for when there's only one. Something like this:
DECLARE
v_type VARCHAR2 (20);
min_length NUMBER;
max_length NUMBER;
v_count NUMBER;
-- user-defined exception
x_single_route exception;
pragme expcetion_init(x_single_route, -20001);
BEGIN
v_type := '&InsertTypeRoute';
IF v_type = 'Multi-Lane Divided' OR
v_type = 'Paved Divided' OR
v_type = 'Paved Undivided'
THEN
SELECT MIN(LENGTH_KM), MAX(LENGTH_KM), COUNT(LENGTH_KM) INTO min_length, max_length, v_count
FROM TBLROUTE WHERE TYPE = v_type;
IF v_count > 1 THEN
DBMS_OUTPUT.PUT_LINE('The minimum length is: ' || TO_CHAR(min_length));
DBMS_OUTPUT.PUT_LINE('The maximum length is: ' || TO_CHAR(max_length));
DBMS_OUTPUT.PUT_LINE ('Total number of '|| v_type ||' route is: ' || TO_CHAR(v_count));
ELSE
raise x_single_route;
END IF;
EXCEPTION
WHEN x_single_route THEN
DBMS_OUTPUT.PUT_LINE ('Route has only one leg');
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Route type cannot be found');
END;
/
Generally it is good practice to RAISE exceptions: users want to know when something goes wrong. (Although as this appears to be a user-facing program, so it's slightly different.)
...
EXCEPTION
WHEN x_single_route THEN
DBMS_OUTPUT.PUT_LINE ('Route has only one leg');
RAISE;
WHEN NO_DATA_FOUND THEN
....
You could use the RAISE_APPLICATION_ERROR procedure to raise a particular exception in the user-defined range (-20000..-20999), then define an exception so you can catch it. Something like the following should work:
DECLARE
SOMETHING_UNWANTED_HAPPENS BOOLEAN := TRUE;
BEGIN
IF SOMETHING_UNWANTED_HAPPENS THEN
RAISE_APPLICATION_ERROR(-20001, 'Something I didn''t want happened');
END IF;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -20001 THEN
DBMS_OUTPUT.PUT_LINE('My user-defined exception was raised');
-- Do whatever else you want to do to handle this exception
ELSE
DBMS_OUTPUT.PUT_LINE('Something else happened');
END IF;
END;
Or you could declare an EXCEPTION variable, initialize it with PRAGMA EXCEPTION_INIT, and then use it like any other exception:
DECLARE
my_exception EXCEPTION;
PRAGMA EXCEPTION_INIT(my_exception, -20001);
SOMETHING_UNWANTED_HAPPENS BOOLEAN := TRUE;
BEGIN
IF SOMETHING_UNWANTED_HAPPENS THEN
RAISE my_exception;
END IF;
EXCEPTION
WHEN my_exception THEN
DBMS_OUTPUT.PUT_LINE('My user-defined exception was raised');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Something else happened');
END;

Resources