What exact exception to be caugth while calling TO_DATE in pl/sql code - oracle

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

Related

Is no-data-found exception not raised implicitly?

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.

PL/SQL value_error exception not getting caught

This is my Department table:
create table Department(
DeptNo int primary key,
DeptName varchar2(21) not null,
DeptLocation varchar2(13) not null
);
I am trying to insert value for DeptName column with length more than accepted i.e. 21, which means I should get "VALUE_ERROR" exception.
The plsql code I am running is:
begin
insert into department values(1, 'Some random department name', 'SomeLocation');
exception
when value_error then
dbms_output.put_line('Cannot store the value!');
end;
As I am trying to catch the exception, it is not getting caught. I am getting the error:
ORA-12899: value too large for column "SQL_ZIRHWMLFPCEAKPGYGJJZLSIFI"."DEPARTMENT"."DEPTNAME" (actual: 27, maximum: 21) ORA-06512: at line 2
ORA-06512: at "SYS.DBMS_SQL", line 1721
But if I change my exception from "value_error" to "others"
begin
insert into department values(1, 'Some random department name', 'SomeLocation');
exception
when others then
dbms_output.put_line('Cannot store the value!');
end;
then I get the expected output
Cannot store the value!
Where could I have gone wrong? Please let me know. Thanks!
PS: I am running all the code on livesql.oracle.com
Ideally, what you are using is correct and it should had worked as desired. But the exception VALUE_ERROR behaves differently in somecases. See the below illustrative example.
As per the documentation value_error comes when there is an
arithmetic, conversion, truncation, or size-constraint error occurs.
For example, when your program selects a column value into a character
variable, if the value is longer than the declared length of the
variable, PL/SQL aborts the assignment and raises VALUE_ERROR. In
procedural statements, VALUE_ERROR is raised if the conversion of a
character string into a number fails.
The last line says, In procedural statements, VALUE_ERROR is raised if the conversion of a character string into a number fails., but when i run this in a block it rasied INVALID_NUMBER exception.
SQL> declare
2 n number;
3 begin
4 select to_number('a')
5 into n
6 from dual
7 ;
8 exception
9 when value_error
10 then
11 dbms_output.put_line ('Value Error');
12 when invalid_number
13 then
14 dbms_output.put_line ('Invalid Number');
15 end;
16 /
Invalid Number
PL/SQL procedure successfully completed.
I expected that it would raise the VALUE_ERROR but it didn't. So it might be the case that Oracle was not able to raise value_error in your case and when you used WHEN OTHERS it was caught.
Edit:
Ok. So is it possible somehow to catch value_error exception by giving
the value longer than the declared length of the variable?
Explicit Raise of System Exception : Not very elegant but you can do it as below.
declare
var int;
var1 varchar2(21);
var2 varchar2(13);
begin
var1:='Some random department name';
var2:= 'SomeLocation'
If var1 > 21 then
RAISE VALUE_ERROR;
END IF;
If var2 > 13 then
RAISE VALUE_ERROR;
END IF;
insert into department values(1, var1, var2);
exception
when value_error then
dbms_output.put_line('Cannot store the value!');
end;
VALUE_ERROR was not the exception raised when you ran your code, if you want, you can defined an EXCEPTION and catch it, see below code for sample,
DECLARE
ORA_12899 EXCEPTION;
PRAGMA EXCEPTION_INIT(ORA_12899, -12899);
begin
insert into department values(1, 'Some random department name', 'SomeLocation');
exception
when ORA_12899 then
dbms_output.put_line('Cannot store the value!');
end;
/
Below code will have a VALUE_ERROR;
DECLARE
ORA_12899 EXCEPTION;
PRAGMA EXCEPTION_INIT(ORA_12899, -12899);
v_dept VARCHAR2(20);
begin
v_dept := 'Some random department name';
insert into department values(1, v_dept, 'SomeLocation');
exception
when ORA_12899 then
dbms_output.put_line('Cannot store the value!');
end;
/

Exclude Extra Error Information from RAISE_APPLICATION_ERROR

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

Where oracle Stores user defined exceptions?

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.

Testing exception handling in Oracle 11g

I have this oracle code
FUNCTION get_enc_val(p_in IN VARCHAR2,
p_key IN VARCHAR2
)
RETURN raw
IS
p_title_procedure_name VARCHAR2(100) := 'get_enc_val';
l_enc_val RAW(2000);
l_mod PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_AES128 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5;
v_key VARCHAR2(16);
encryption_ex Exception;
BEGIN
v_key := RPAD(SUBSTR(TRIM(p_key), 1, 16), 16, '0');
l_enc_val := DBMS_CRYPTO.encrypt(UTL_RAW.cast_to_raw(p_in), l_mod, UTL_RAW.cast_to_raw(v_key));
RAISE encryption_ex;
RETURN l_enc_val;
EXCEPTION
WHEN OTHERS THEN
service_func.log_error(p_title_package_name || '.' || p_title_procedure_name, 'Proc', NULL, SYSDATE, SQLERRM, p_in || '~' || p_key);
RETURN 'Encryption_ERROR';
END;
When I run this I get ORA-06510 Unhandled user-defined exception while it should really return the string 'Encryption_ERROR'.What gives? It goes to the Exception block, because I see the result of log_error function. Question is, isn't the Exception block supposed to HANDLE ANY exception?
I am a bit confused.
The problem is that your second RETURN statement is returning a VARCHAR2 while your function is declared to return a RAW. You could fix that by calling UTL_RAW.CAST_TO_RAW, i.e.
EXCEPTION
WHEN OTHERS THEN
service_func.log_error(p_title_package_name || '.' ||
p_title_procedure_name,
'Proc',
NULL,
SYSDATE,
SQLERRM,
p_in || '~' || p_key);
RETURN utl_raw.cast_to_raw( 'Encryption_ERROR' );
END;
If I declare two functions, one that returns a hard-coded string and one that returns a RAW, you'll see the difference (I'm removing the DBMS_CRYPTO calls and the LOG_ERROR call). If I declare a function that returns a RAW, you get a result back (though a human would have to convert the raw back into a string to make sense of the result)
SQL> ed
Wrote file afiedt.buf
1 create or replace function throw_exception
2 return raw
3 is
4 my_exception exception;
5 begin
6 raise my_exception;
7 exception
8 when others then
9 return utl_raw.cast_to_raw( 'Foo' );
10* end;
SQL> /
Function created.
SQL> select throw_exception
2 from dual;
THROW_EXCEPTION
-----------------------------------------------------------------------------
466F6F
If I just return a string, I'll get the same exception you were getting
SQL> ed
Wrote file afiedt.buf
1 create or replace function throw_exception2
2 return raw
3 is
4 my_exception exception;
5 begin
6 raise my_exception;
7 exception
8 when others then
9 return 'Foo';
10* end;
SQL> /
Function created.
SQL> select throw_exception2
2 from dual;
select throw_exception2
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: hex to raw conversion error
ORA-06512: at "SCOTT.THROW_EXCEPTION2", line 9
ORA-06510: PL/SQL: unhandled user-defined exception
Of course, the other option would be to declare that the function returns a VARCHAR2. But I would much rather have hashes and encrypted data in a RAW than a VARCHAR2 so that you never have to worry about things like character set conversion issues mangling the data.
Since you are sure that service_func.log_error(...); is not raising the error, the error must be thrown by the calling procedure/function.
And here's something that raises the same error.
create or replace function abc return raw is
begin
return 'Encryption_ERROR';
end;
/
declare
r raw(50);
begin
r := abc;
end;
/

Resources