migrate raiserror from SYBASE ASE to ORACLE - oracle

I am migrating stored procedures to pl/sql blocks, and I have little knowledge in error handling in oracle and nothing in sybase can you help me.
example: sql SYBASE
DELETE table_1
WHERE N=0
SELECT #myrowcount = ##rowcount, #myerror = ##error, #mystat = ##sqlstatus
if (#myerror <> 0)
begin
raiserror 40900 "Error: When Generating Exception List #table_1 (error= %1!)", #mystat
select #cod_err= 1
return #cod_err
end
Edit: sql oracle i dont know if this is right
begin
DELETE table_1
WHERE N=0
EXCEPTION WHEN OTHERS THEN
SWV_error := SQLCODE;
end;
v_mi_error := SWV_error;
if v_mi_error != 0 then
RAISE_APPLICATION_ERROR(-40900,'Error: When Generating Exception List table_1');
return;
end if;

Which error do you expect for delete? It'll either delete some rows, or won't. If table (or column) doesn't exist, code wouldn't even compile so you wouldn't reach runtime error.
Anyway: in Oracle, it looks like this:
begin
delete table_1 where n = 0;
exception
when others then
raise_application_error(-20000, 'Error: ' || sqlerrm);
end;
/
others is exception which handles various things; you don't really care which error it is, as could be any error. Oracle reserved error codes from -20000 to -20999 for us, developers so you have to pick one of these (which means that -40900 won't work).
sqlerrm is error message (its description). If you want, you can get its code via sqlcode.
Example which shows how it actually works (not with delete, though) is query that fetches employee name for non-existent employee number. That raises predefined no_data_found error (whose code is -01403) so you could handle it, directly, or - as my previous example shows - use others.
SQL> declare
2 l_name varchar2(10);
3 begin
4 select ename
5 into l_name
6 from emp
7 where empno = -1;
8 exception
9 when others then
10 raise_application_error(-20000, 'Error: ' || sqlcode ||': '|| sqlerrm);
11 end;
12 /
declare
*
ERROR at line 1:
ORA-20000: Error: 100: ORA-01403: no data found
ORA-06512: at line 10
SQL>

Related

Duplicate error message when error handling

I have this procedure:
CREATE OR REPLACE PROCEDURE procA (paramA VARCHAR2, paramB VARCHAR2, output_value OUT VARCHAR2)
IS
BEGIN
IF paramA IS NOT NULL THEN
BEGIN --1
SELECT columA
INTO output_value
FROM tableA
WHERE columnB = paramA;
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- 2
SELECT columB
INTO output_value
FROM tableB
WHERE columnC = paramB;
END;
ELSE
SELECT columB
INTO output_value
FROM tableB
WHERE columnC = paramB;
END IF;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR (-20008, 'Error: ' || SQLCODE || ' ' || SUBSTR (SQLERRM, 1, 200));
END procA;
I run this call:
DECLARE
output VARCHAR2 (10);
BEGIN
procA ('valueA', 'valueB', output);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE (SQLERRM); --3
END;
With these parameters the first SELECT statement gets a NO_DATA_FOUND (1). And handled with the that EXCEPTION. Then, I run the second SELECT statement (2) and I get again, a NO_DATA_FOUND exception.
Why do I get a duplicate NO_DATA_FOUND message in (3), like this:
ORA-20008: Error: 100 ORA-01403: no data found
ORA-01403: no data found
The first exception is handled, I expected that the last error handling will return just one message.
You aren't seeing a single error being duplicated; you're seeing two errors, which happen to be the same.
If you add a format_error_stack call to your final exception hander you can see that both of the thrown exceptions are in that stack:
...
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_STACK);
RAISE_APPLICATION_ERROR (-20008, 'Error: ' || SQLCODE || ' ' || SUBSTR (SQLERRM, 1, 200));
END procA;
/
The call from your anonymous block then shows:
ORA-01403: no data found
ORA-06512: at "<schema>.PROCA", line 13
ORA-01403: no data found
ORA-06512: at "<schema>.PROCA", line 6
ORA-20008: Error: 100 ORA-01403: no data found
ORA-01403: no data found
db<>fiddle
It might be a bit clearer if you vary the errors, e.g.:
declare
l_dummy varchar2(1);
begin
begin
select 'x' into l_dummy from all_users;
exception when too_many_rows then
select 'x' into l_dummy from all_users where 1=0;
end;
exception when others then
dbms_output.put_line(dbms_utility.format_error_stack);
dbms_output.put_line('caught <' || sqlerrm || '>');
end;
/
which produces:
ORA-01403: no data found
ORA-06512: at line 7
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 5
caught <ORA-01403: no data found
ORA-01422: exact fetch returns more than requested number of rows>
db<>fiddle
The SQLERRM call combines both error messages, though the documentation doesn't seem to say that will happen. Oracle support note 2438311.1 seems to suggest it shouldn't, but it does all of the db<>fiddle versions and in 12.2.0.1 and 19.11 at least.
But, what if I just want the last one?
If you're on Oracle 12c or later, you can use UTL_CALL_STACK.ERROR_MSG(1) to get the first error from the stack, instead of using SQLERRM.
...
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR (-20008,
'Error: ' || SQLCODE || ' ' || SUBSTR (UTL_CALL_STACK.ERROR_MSG(1), 1, 200));
END procA;
/
which will now just show:
ORA-20008: Error: 100 no data found
db<>fiddle (and another one for my earlier example.)
You can read more about that function in the documentation.
There is a difference between handling and catching an exception.
You're using RAISE_APPLICATION_ERROR, which throws the exception to the caller although you've caught it once and since you catch it two times - you have two errors.

Catching multiple exception at once in oracle

Please let me know whether it is possible to catch multiple exception at same time in oracle. Not like 1 user defined and 1 is oracle default .I need to catch multiple user defined exception at same time . Kindly let me know how to do .
Thank you !
Certainly, there is - if I understood the question correctly. It is called WHEN OTHERS. Though, people usually misuse it, especially when they use
exception
when others then
null;
end;
as it successfully hides any errors that might appear. WHEN OTHERS is OK during development process, but might be really bad in production, especially if it doesn't contain raise.
Yes, you can do what you want from "When Others" as indicated by #Littlefoot or bulk processing errors (not covered here). But additionally you can have an OR condition exception name clause on the WHEN . It's not very useful as generally requires more code the 2 separate WHEN condition, but it is valid syntax. The following demonstrates various error definition methods and exception processing.
create table except_demo ( id integer, col1 varchar2(20));
insert into except_demo (id, col1)
select 5,'OK' from dual union all
select 6,'Too Many' from dual union all
select 6,'Still' from dual;
select id, count(*) from except_demo group by id;
create or replace procedure catcher(which_in integer, select_in boolean default False)
is
e_user_1 exception;
e_user_2 exception;
invalid_which_range exception;
appErr_inactive_acct exception;
sample_ora_error exception;
pragma exception_init (sample_ora_error, -00060);
rae exception;
rae_num constant integer := -20100;
pragma exception_init (rae, -20100);
col1_value except_demo.col1%type;
begin
dbms_output.put( 'Enter catcher(' || which_in || ') Result=>');
if which_in > 8
then raise invalid_which_range;
end if ;
if select_in
then
select col1
into col1_value
from except_demo
where id = which_in;
dbms_output.put_line('Select Successful 1 row selected.');
else
case which_in
when 1 then raise e_user_1;
when 2 then raise e_user_2;
when 3 then raise appErr_inactive_acct;
when 4 then raise sample_ora_error;
else raise_application_error(rae_num, 'Which_In=' || which_in || ' invalid. Please specify number 1-7 only');
end case;
end if;
exception
when e_user_1
then dbms_output.put_line('Error e_user_1'); -- user error
when e_user_2
then dbms_output.put_line('Error e_user_2');
when no_data_found or too_many_rows
then dbms_output.put_line('Select except_demo where id=' || which_in ||'; Returned 0 or more than 1 row. Must return exactly 1.' ); -- oracle predefined error
when sample_ora_error
then dbms_output.put_line('Ora Error:: ' || sqlerrm ); -- oracle error NOT predefined
when appErr_inactive_acct
then dbms_output.put_line('Error Account id ' || which_in || ' is inactive.'); -- user error
when rae
then dbms_output.put_line(sqlerrm);
end catcher;
declare
do_select boolean;
begin
for i in 1..9
loop
do_select := (i between 5 and 7);
catcher(i,do_select);
end loop;
exception
when others
then
dbms_output.put_line('Error returned from catcher=>' || sqlerrm);
raise;
end ;
drop procedure catcher;
drop table except_demo;
In a live environment the dbms_output statement would be replaced writing the message and other information to a exception log table and NOT dbms_output.
I have a very minor disagreement with Littlefoot. I firmly believe that what ever is written in development, whether intended or not, will run in production. Too often it is the unintended that gets you into trouble. Therefore the example of a misused WHEN OTHERS is invalid even in development.

Find bad dynamic SQL statements containing syntax errors in Oracle

I was wondering if there is a way to find dynamic SQL statements whose execution broke during runtime in case there was no proper exception handling in the PL/SQL program unit that called the dynanic SQL.
procedure will_crash is
begin
-- 1000 dynamic sql statements here ..
execute immediate 'updaXte dual set X = ''Z'' ' ;
-- ... and 1000 more dynamic sql statements here ..
commit;
end; --> NO proper exception handling for logging the last sql statement
In case a nighttime scheduled program unit contains hundreds of dynamic sql statements, I'd like to find out which one broke without debugging. Does Oracle log anything in its system views?
In you're example there's no need at all to use dynamic SQL, so the easiest solution is to rewrite it as
procedure will_crash is
begin
-- 1000 dynamic sql statements here ..
updaXte dual set X = ''Z''; -- Error at compile time!!
-- ... and 1000 more dynamic sql statements here ..
commit;
end; --> NO proper exception handling for logging the last sql statement
If the real procedure uses dynamic SQL because the SQL statements are saved elsewhere (variables or SQL table), and we're talking only about syntax error, you can achieve your objective before executing statements using DBMS_SQL package.
Here's an example:
DECLARE
lc_good VARCHAR2(200) := 'SELECT 1 FROM dual';
lc_bad VARCHAR2(200) := 'SEL1ECT a FROM dual';
lc_cursor NUMBER;
BEGIN
lc_cursor := SYS.DBMS_SQL.OPEN_CURSOR;
BEGIN
SYS.DBMS_SQL.PARSE(lc_cursor, lc_good, DBMS_SQL.V7);
dbms_output.put_line('Statement 1 is GOOD');
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Statement 1 is BAD: ' || SQLERRM);
END;
BEGIN
SYS.DBMS_SQL.PARSE(lc_cursor, lc_bad, DBMS_SQL.V7);
dbms_output.put_line('Statement 2 is GOOD');
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Statement 2 is BAD: ' || SQLERRM);
END;
SYS.DBMS_SQL.close_cursor(lc_cursor);
END;
The function output is the following:
Statement 1 is GOOD
Statement 2 is BAD: ORA-00900: ...
Note that the code only parses the SQL statements, it don't executes them.

How to handle general exceptions in PL/SQL

I looked at Google and here but couldn't find an answer for this.
I don't want to treat all exceptions in Oracle.
What I want is just get the return code of the last statement and check if it is 0 (zero). If it is, the command was executed ok. If not, there was some error and then I want the procedure to exit and raise a message saying only that there was an error and the command that caused that error.
Thanks in advance!
If I'm interpreting your question correctly, it sounds like you want to ignore all exceptions and manually check the SQLCODE after every statement. If my understanding is correct, I'm afraid there's not really a way to do that in PL/SQL. When errors occur the system WILL raise an exception - there's no way around it. What you CAN do is to record a description of where the program is in its execution and print that from a generic exception handler, similar to the following:
PROCEDURE SOME_PROCEDURE IS
strCheckpoint VARCHAR2(2000);
rowSome_table SOME_TABLE%ROWTYPE;
BEGIN
strCheckpoint := 'SELECT FROM SOME_TABLE';
SELECT *
INTO rowSome_table
FROM SOME_TABLE
WHERE SOME_COLUMN = 42;
strCheckpoint := 'UPDATE SOME_OTHER_TABLE';
UPDATE SOME_OTHER_TABLE
SET A_COLUMN = rowSome_table.A_COLUMN
WHERE KEY_COLUMN = rowSome_table.KEY_COLUMN;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Something happened at checkpoint ''' ||
strCheckpoint ||
''' SQLCODE=' || SQLCODE ||
' SQLERRM=' || SQLERRM);
RETURN;
END; -- SOME_PROCEDURE
Share and enjoy.
Not sure I got your problem right but does this look like you need ?
SQL> create function get_number return number
2 is
3 begin
4 return 1;
5 end;
6 /
SQL> begin
2 if get_number != 0 then
3 raise_application_error(-20000,'Error raised !');
4 end if;
5 end;
6 /
begin
*
Error in line 1:
ORA-20000: Error raised !
ORA-06512: на line 3
or
SQL> declare
2 user_def_exc exception;
3 begin
4 if get_number!=0 then
5 raise user_def_exc;
6 end if;
7 exception
8 when user_def_exc then
9 dbms_output.put_line('We ave got a problem');
10 end;
11 /
We ave got a problem
You can use the following in SQLPLus:
SQL>whenever sqlerror exit 1
This will terminate the execution of your script upon an error with exit value 1

oracle handling no data from query

I am writing a trigger to check if an employee is allocated to two flights that overlap.
It would be something like:
select flight_id from flight
where arrival_time > :new.departure_time
and departure_time < :new.arrival_time;
if flight_id is empty
[do nothing]
if flight_id exists
[raise application error]
Can anyone help me out in how I would have to code the conditional logic there? This is my first time working with oracle (university coursework).
SELECT ... INTO is your friend. It will raise an exception, you catch it, do nothing, otherwise and raise your own error.
select flight_id into v
from flight
where arrival_time > :new.departure_time
and departure_time < :new.arrival_time;
raise_application_error(-20000, 'not good');
exception
when NO_DATA_FOUND
then return 1
when others
then raise_application_error(-20011,'really good');
DECLARE
V_some_varible NUMBER;
BEGIN
Seclect 1 into v_some_varible from dual where 1 = 0;
EXCEPTION -- exception handlers begin
WHEN NO_DATA_FOUND THEN
INSERT INTO errors (message) VALUES ('no data found');
WHEN OTHERS THEN -- handles all other errors
ROLLBACK;
END;
Note the 1 = 0 to force the no data found exception. This example should work in any Oracle database with the exception of the insert into an errors table.

Resources