Is there oracle table that stores user defined exceptions?
No.
User-defined exceptions are, like other variables, defined in PL/SQL blocks and have whatever scope the PL/SQL variable would have. So, for example
DECLARE
my_exception EXCEPTION;
BEGIN
RAISE my_exception;
EXCEPTION
WHEN my_exception
THEN
dbms_output.put_line( 'Caught my_exception' );
END;
will create the user-defined exception my_exception but the exception will only exist for the scope of the anonymous PL/SQL block. You can define exceptions in packages so that they can be referenced by multiple PL/SQL blocks. And you can use the exception_init pragma to associate user-defined exceptions with particular error codes
SQL> ed
Wrote file afiedt.buf
1 DECLARE
2 my_exception EXCEPTION;
3 pragma exception_init( my_exception, -20001 );
4 BEGIN
5 RAISE my_exception;
6* END;
SQL> /
DECLARE
*
ERROR at line 1:
ORA-20001:
ORA-06512: at line 5
Or you can use the raise_application_error function either alone or in concert with user-defined exception variables
SQL> ed
Wrote file afiedt.buf
1 DECLARE
2 my_exception EXCEPTION;
3 pragma exception_init( my_exception, -20001 );
4 BEGIN
5 RAISE_APPLICATION_ERROR( -20001, 'This is my error text' );
6 EXCEPTION
7 WHEN my_exception
8 THEN
9 dbms_output.put_line( 'Caught my_exception' );
10 dbms_output.put_line( sqlerrm );
11* END;
SQL> /
Caught my_exception
ORA-20001: This is my error text
PL/SQL procedure successfully completed.
There is no data dictionary table to store user-defined exceptions because there are so many (potentially conflicting) ways that your code might define those exceptions. From a good exception management standpoint, you would generally want to come up with a consistent way of defining your application-specific exceptions and sticking to that approach. Personally, I like a package that defines all my exceptions and associates them with error codes
SQL> ed
Wrote file afiedt.buf
1 create or replace package error_pkg
2 as
3 invalid_name exception;
4 pragma exception_init( invalid_name, -20001 );
5 invalid_address exception;
6 pragma exception_init( invalid_address, -20002 );
7* end;
SQL> /
Package created.
Assuming all my user-defined exceptions are all defined like this, I can go to the package definition for all my definitions.
Related
question 1:
I noticed the no-data-found exception not raised implicitly, do we need to raise them manually/explicitly?
Question 2:
I writing a SP package with 4 procedures in it and i'm writing below procedures on a single table.
the exception handling is repetitive in each procedure. is there any guidance/coding standard to keep it in a single place procedure#5 or function and call it there.
Select
Update
Insert
Delete
I guess if I keep it in a function it would raise the exception and return to the called procedure and continue to run ? but when we raise a exception the program should stop , right?
You have run into the only exception in PL/SQL exception handling - ORA-1403: no data found is suppressed when it is generated by a function called in a SQL context.
No data found exceptions work fine in PL/SQL anonymous blocks:
SQL> declare
2 v_number number;
3 begin
4 select 1 into v_number from dual where 1=0;
5 end;
6 /
declare
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 4
And no data found also works as expected with a function called in a PL/SQL statement:
SQL> create or replace function exception_no_data_found return number is
2 v_number number;
3 begin
4 select 1 into v_number from dual where 1=0;
5 return v_number;
6 end;
7 /
Function created.
SQL> declare
2 v_number number;
3 begin
4 v_number := exception_no_data_found;
5 end;
6 /
declare
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "JHELLER.EXCEPTION_NO_DATA_FOUND", line 4
ORA-06512: at line 4
But when calling the function in a SQL context, the exception disappears:
SQL> select exception_no_data_found from dual;
EXCEPTION_NO_DATA_FOUND
-----------------------
I think the reason for this is that SQL internally uses the no data found exception to let the system know there are no more rows, so it's not always an exception. (This behavior is probably a bug but has been around for so long that it'll never change.)
To raise that exception in this situation, you must manually catch and raise a different exception like this:
SQL> create or replace function exception_no_data_found return number is
2 v_number number;
3 begin
4 select 1 into v_number from dual where 1=0;
5 return v_number;
6 exception when no_data_found then
7 raise_application_error(-20000, 'No data found.');
8 end;
9 /
Function created.
SQL> select exception_no_data_found from dual;
select exception_no_data_found from dual
*
ERROR at line 1:
ORA-20000: No data found.
ORA-06512: at "JHELLER.EXCEPTION_NO_DATA_FOUND", line 7
But the above situation is by far the weirdest part about Oracle exception handling. Other than this scenario, in general you are almost always better off by not doing any exception handling. Just let the program break; the exceptions will propagate up, and the application will get an exception that includes the full error message and the exact line number of the error. In practice, that information is almost always enough to debug any problems. Only add custom exception handling when you know for sure that you need to gather extra data.
I have raised an error message in a PL/SQL trigger and it works fine except that it returns more than the error I specify to the application. In addition to the custom error I get information about the line that the error happened on and the trigger.
For example it will get
ORA-20111: There is a custom error here
ORA-06512: at "{schema_name}.{trigger_name}", LINE 2
ORA-04088: error during execution of trigger {schema_name}.{trigger_name}<br>
.Operation canceled.
What I actually want is:
ORA-20111: There is a custom error here
How do I remove the extra information from the error message before it is returned to my application? My testing code below...
CREATE OR REPLACE TRIGGER CUSTOM_ERROR
BEFORE INSERT OR UPDATE ON {SCHEMA_NAME}.{TABLE_NAME} FOR EACH ROW
BEGIN
RAISE_APPLICATION_ERROR(-20111, 'There is a custom error here');
END;
You could use RAISE_APPLICATION_ERROR.
For example,
SQL> DECLARE
2 custom_err EXCEPTION;
3 PRAGMA EXCEPTION_INIT( custom_err, -20099 );
4 BEGIN
5 raise_application_error( -20099, 'This is a custom error' );
6 EXCEPTION
7 WHEN custom_err THEN
8 dbms_output.put_line( sqlerrm );
9 END;
10 /
ORA-20099: This is a custom error
PL/SQL procedure successfully completed.
SQL>
PRAGMA EXCEPTION_INIT is to give a custom error number, which could vary in a range from -20001 to -20999
However, you need to take care of the already-defined exceptions from being raised.
For example,
SQL> DECLARE
2 custom_err EXCEPTION;
3 PRAGMA EXCEPTION_INIT( custom_err, -20099 );
4 v number;
5 BEGIN
6 SELECT empno INTO v FROM emp WHERE empno = 1234;
7 raise_application_error( -20099, 'This is a custom error' );
8 EXCEPTION
9 WHEN custom_err THEN
10 dbms_output.put_line( sqlerrm );
11 END;
12 /
DECLARE
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 6
SQL>
There is a NO_DATA_FOUND exception thrown. You could suppress that, however, it will leave the error stack with additional messages.
SQL> DECLARE
2 custom_err EXCEPTION;
3 PRAGMA EXCEPTION_INIT( custom_err, -20099 );
4 v number;
5 BEGIN
6 SELECT empno INTO v FROM emp WHERE empno = 1234;
7 raise_application_error( -20099, 'This is a custom error' );
8 EXCEPTION
9 WHEN no_data_found THEN
10 raise_application_error( -20099, 'This is a custom error' );
11 WHEN custom_err THEN
12 dbms_output.put_line( sqlerrm );
13 END;
14 /
DECLARE
*
ERROR at line 1:
ORA-20099: This is a custom error
ORA-06512: at line 10
SQL>
I would always want to log the errors as verbose as possible. The raise_application_error is good for a custom message to be displayed on the application, however, I would log all the errors in the program.
Please have a look at:
dbms_utility.format_error_stack
dbms_utility.format_error_backtrace
I have below code to_date('1311313', 'yymmdd') which actually throws exception with saying invalid month. Which is can manage as
exception
when others then
sop('date format is wrong');
Here the problem is everything will get caught which I do not want to do as if some other error will occur then also it will pass the message date format is wrong. I also do not want to create a user defined exception. Just want to know which exception is being thrwon out so that I can use in my code like below
exception
when name_of_exception then
sop('date format is wrong');
The Internally Defined Exceptions section of the Oracle Database PL/SQL Language Reference says:
An internally defined exception does not have a name unless either PL/SQL gives it one (see "Predefined Exceptions") or you give it one.
You code throws the exception ORA-01830:
SQL> select to_date('1311313', 'yymmdd') from dual
*
ERROR at line 1:
ORA-01830: date format picture ends before converting entire input string
Since it is not one of the Predefined Exceptions, you must give it a name yourself:
declare
ex_date_format exception;
pragma exception_init(ex_date_format, -1830);
v_date date;
begin
select to_date('1311313', 'yymmdd')
into v_date
from dual;
exception
when ex_date_format then
sop('date format is wrong');
end;
/
There are at least two approaches to handle different exceptions raised during an attempt to convert character literal to a value of DATE data type:
Define as many exception names and associate them with Oracle error codes, using exception_init pragma, as many exceptions to_date() function is able to raise.
Create a stand alone, or part of a package, wrap-up function for to_date() function, with one when others exception handler.
Personally I lean toward the second one.
SQL> create or replace package util1 as
2 function to_date1(
3 p_char_literal in varchar2,
4 p_date_format in varchar2
5 ) return date;
6 end;
7 /
Package created
SQL> create or replace package body util1 as
2
3 function to_date1(
4 p_char_literal in varchar2,
5 p_date_format in varchar2
6 ) return date is
7 begin -- in this situation it'll be safe to use `when others`.
8 return to_date(p_char_literal, p_date_format);
9 exception
10 when others then
11 raise_application_error(-20001, 'Not a valid date');
12 end;
13
14 end;
15 /
Package body created
Now, there is only one exception to handle, -20001 Not a valid date, and your PL/SQl block might look like this:
SQL> set serveroutput on;
-- [1] otherwise, for '1311313' the ORA-01830 exception would be raised
SQL> declare
2 not_a_valid_date exception;
3 pragma exception_init(not_a_valid_date, -20001);
4 l_res date;
5 begin
6 l_res := util1.to_date1('1311313', 'yymmdd');
7 exception
8 when not_a_valid_date then
9 dbms_output.put_line(sqlerrm);
10 -- or other handler sop('date format is wrong');
11 end;
12 /
ORA-20001: Not a valid date
-- [2] otherwise, for '000000' the ORA-01843(not a valid month)
-- exception would be raised
SQL> declare
2 not_a_valid_date exception;
3 pragma exception_init(not_a_valid_date, -20001);
4 l_res date;
5 begin
6 l_res := util1.to_date1('000000', 'yymmdd');
7 exception
8 when not_a_valid_date then
9 dbms_output.put_line(sqlerrm);
10 -- or other handler sop('date format is wrong');
11 end;
12 /
ORA-20001: Not a valid date
Is it a bad practice to do what the code below does? Will bad things happen to me for writing it?
Edit: this is just an example. I would not use dbms_output for any real error reporting.
CREATE OR REPLACE PACKAGE my_package
AS
PROCEDURE master;
END;
/
CREATE OR REPLACE PACKAGE BODY my_package
AS
my_global_interrupt EXCEPTION;
PROCEDURE my_private_procedure
IS
BEGIN
-- in case some flag is raised, raise exception to stop process and prepare for resume
RAISE my_global_interrupt;
END;
PROCEDURE master
IS
BEGIN
my_private_procedure;
EXCEPTION
WHEN my_global_interrupt THEN
dbms_output.put_line('global interrupt, ');
-- prepare to resume
END;
END;
/
On the contrary globally defined user exceptions is good practice. Consider the following skeleton of a package body.
create or replace package body my_pkg
as
my_x1 exception;
my_x2 exception;
my_x3 exception;
PROCEDURE p1 is
begin
...
exception
when no_data_found then raise my_x1;
end p1;
PROCEDURE p2 is
begin
...
exception
when no_data_found then raise my_x2;
end p2;
PROCEDURE p3 is
begin
...
exception
when no_data_found then raise my_x3;
end p3;
PROCEDURE master is
begin
p1;
p2;
p3;
exception
when my_x1 then do_this;
when my_x2 then do_that;
when my_x3 then do_the_other;
end master;
end my_pkg;
/
The use of globally declared exceptions makes exception handling in the master procedure easier.
Also, bear in mind that sometimes we want to propagate the exception beyond the package, to say a program which calls our publicly declared procedure. We can do that by defining our exceptions in the package spec. This means other proecdures can reference them...
SQL> begin
2 my_pkg.master;
3 exception
4 when my_pkg.my_public_x1
5 then dbms_output.put_line('oh no!');
6 end;
7 /
oh no!
PL/SQL procedure successfully completed.
SQL>
We can also associate such exceptions with specific error numbers, so that they are recognisable even if the calling procedure doesn't explicitly handled them.
SQL> exec my_pkg.master
BEGIN my_pkg.master; END;
*
ERROR at line 1:
ORA-20999:
ORA-06512: at "APC.MY_PKG", line 32
ORA-06512: at line 1
SQL>
That's (slightly) more helpful than the generic ORA-06510 error.
Looks reasonable enough to me, provided you're happy that after the interrupt condition it's OK to resume processing. If you are going to log the interrupt in some way, it's probably better to insert a row into a log table using an autonomous transaction. You won't see anything from DBMS_OUTPUT until the whole procedure finishes. Then you'll see all the DBMS_OUTPUT at once.
I need to handle the ORA-01400 error (cannot insert NULL into ("SCHEMA"."TABLE_NAME"."COLUMN_NAME") ) using a exception handle.
ORACLE Predefine a few Exceptions like (ACCESS_INTO_NULL, ZERO_DIVIDE and so on), but apparently does not define an Exception for the ORA-01400 error, how do I handle this particular error code?
I need something like this (other suggestions are accepted).
....
...
INSERT INTO MY_TABLE (CODE, NAME) VALUES (aCode,aName);
COMMIT;
EXCEPTION
WHEN NULL_VALUES THEN /* i don't know this value , exist?*/
Do_MyStuff();
WHEN OTHERS THEN
raise_application_error(SQLCODE,MY_OWN_FORMAT_EXCEPTION(SQLCODE,SQLERRM),TRUE);
END;
The pre-defined PL/SQL exceptions are special to Oracle. You really can't mess with those. When you want to have a set of predefined exceptions of your own you can't declare them "globally" like the standard ones. Instead, create an exceptions package which has all of the exception declarations and use that in your application code.
Example:
CREATE OR REPLACE PACKAGE my_exceptions
AS
insert_null_into_notnull EXCEPTION;
PRAGMA EXCEPTION_INIT(insert_null_into_notnull, -1400);
update_null_to_notnull EXCEPTION;
PRAGMA EXCEPTION_INIT(update_null_to_notnull, -1407);
END my_exceptions;
/
Now use the exception defined in the package
CREATE OR REPLACE PROCEDURE use_an_exception AS
BEGIN
-- application specific code ...
NULL;
EXCEPTION
WHEN my_exceptions.insert_null_into_notnull THEN
-- application specific handling for ORA-01400: cannot insert NULL into (%s)
RAISE;
END;
/
Source: http://www.orafaq.com/wiki/Exception
you can define your own exceptions, like variables (they will have the same scope as other variables so you can define package exception, etc...):
SQL> DECLARE
2 NULL_VALUES EXCEPTION;
3 PRAGMA EXCEPTION_INIT(NULL_VALUES, -1400);
4 BEGIN
5 INSERT INTO t VALUES (NULL);
6 EXCEPTION
7 WHEN null_values THEN
8 dbms_output.put_line('null value not authorized');
9 END;
10 /
null value not authorized
PL/SQL procedure successfully completed
You can handle exception by its code like this:
....
...
INSERT INTO MY_TABLE (CODE, NAME) VALUES (aCode,aName);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -1400 THEN
Do_MyStuff();
ELSE
raise_application_error(SQLCODE,MY_OWN_FORMAT_EXCEPTION(SQLCODE,SQLERRM),TRUE);
END IF;
END;
INSERT INTO MY_TABLE (CODE, NAME) VALUES (aCode,aName);
COMMIT;
EXCEPTION
WHEN NULL_VALUES /* i don't know this value , exist?*/
emesg := SQLERRM;
dbms_output.put_line(emesg);
WHEN OTHERS THEN
emesg := SQLERRM;
dbms_output.put_line(emesg);
END;
SQLERRM shows the sql error message
http://www.psoug.org/reference/exception_handling.html