in oracle what is the deference between raising exception and reraising exception 'with simple example please' and what is the deference between exception and normal if statement that print error if it happens?
One big difference between raising an exception vs. re-raising an exception is that with a RAISE; the original error message is preserved, e.g. (this is a contrived example, hopefully you get the idea):
create table t (x varchar2(1));
begin
insert into t values ('aa');
exception
when others then
dbms_output.put_line(sqlerrm);
raise;
end;
ORA-12899: value too large for column "XXSPS"."T"."X" (actual: 2, maximum: 1)
vs.
declare
value_too_large exception;
pragma exception_init (value_too_large, -12899);
begin
insert into t values ('aa');
exception
when value_too_large then
raise value_too_large;
end;
ORA-12899: value too large for column (actual: , maximum: )
In the 2nd case, we raise the "value_too_large" exception which has no reference back to the original exception that had the column name or length information.
When you are inside an exception handler in an exception section, you can re-raise the exception that “got you there” by issuing an unqualified RAISE statement as follows:
RAISE;
Since you do not specify an exception, the PL/SQL runtime engine re-raises the current exception (whose error number would be returned by a call to the SQLCODE function).
Here is an example of using raise in this way:
EXCEPTION
WHEN OTHERS
THEN
send_error_to_pipe (SQLCODE);
RAISE;
END;
Related
Is it possible to know real reason, real ora code (in this case unique key violation) when using
FORALL var_i_idx IN 1..table_of_t.count SAVE EXCEPTIONS
INSERT INTO TABLE_A VALUES (
table_of_t(var_i_idx).var_id);
RETURN retVal;
EXCEPTION
WHEN OTHERS
THEN
IF SQLCODE = -24381
THEN
FOR var_i_idx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
v_action := 'Insert table_of_t';
v_error_text := 'Unexcpected exception SQLCODE: ' || SQL%BULK_EXCEPTIONS (var_i_idx).ERROR_INDEX || ' -- ERROR:' || sqlerrm(SQL%BULK_EXCEPTIONS (var_i_idx).ERROR_CODE);
dbms_output.put_line('Unexcpected exception SQLCODE: '||SQLCODE||' -- ERROR: '||SQLERRM);
DBMS will print following :Unexcpected exception SQLCODE: -24381 -- ERROR: ORA-24381: error(s) in array DML
But is it possible to know real reason ?
Yes, you can get the actual error message, although only the base message. The issue you have is your dbms_output message is for the bulk error not the individual item errors. You get the item error from the ERROR_CODE in the SQL%BULK_EXCEPTIONS collections. Even more you access the actual data causing the exception through ERROR_INDEX. This indexes the entry in the collection named in the forall statement. Skeleton access for error message and bulk collection (where blk_array is the name of the collection used in the forall). See fiddle;
for err_idx in 1 .. sql%bulk_exceptions
loop
msg := sqlerrm(-sql%bulk_exceptions(err_idx).error_code);
val := blk_array(sql%bulk_exceptions(err_idx).error_index);
end loop;
In the fiddle ignore the code setting up the FORALL, that was available for another task entirely. Just concentrate on the Exception section except for the lines:
declare
errors_during_forall exception; -- create name for errors during bulk, forall, processing
pragma exception_init (errors_during_forall, -24381); -- and tie that name to the actual Oracle error number
This allows you to define a name to the exception and then reference that name is the EXCEPTION section.
We can pass error message, error code to front end using USER_DEFINED EXCEPTION or PREDEFINED EXCEPTION (others, SQLERRM, SQLCODE) using OUT PARAMETER MODE, then why we use RAISE_APPLICATION_ERROR procedure?
What is the difference between RAISE_APPLICATION_ERROR and pragma EXCEPTION_INIT?
I have Googled these questions, but can't get a clear answer - that is why posted here.
See this similar question. The answer to both of those is that RAISE_APPLICATION_ERROR is the canonical way to define custom error messages to be displayed in the client application. Yes, you could also pass custom messages back using an OUT parameter, or DBMS_OUTPUT, or something similar, but those are not standardized - you'll have to add code on both the server and client side to handle them.
DECLARE
my_exception EXCEPTION;
PRAGMA EXCEPTION_INIT(my_exception, -20001);
BEGIN
raise my_exception; -- message is default "ORA-20001: "
END;
/
BEGIN
raise_application_error(-20001, 'My custom error message'); -- message is "ORA-20001: My custom error message"
END;
/
This is often useful when you want to give a more helpful, descriptive error message.
DECLARE
age NUMBER;
BEGIN
age := 'hello';
EXCEPTION when VALUE_ERROR then
raise_application_error(-20001, 'Age must be a number.');
END;
/
So instead of a generic "PL/SQL: numeric or value error: character to number conversion error", we can tell the user exactly what the problem is: "Age must be a number".
A user-defined exception doesn't provide any message to the calling application. It'll just get a generic 'ORA-06510: PL/SQL: unhandled user-defined exception'. raise_application_error lets you pass a message describing the actual problem.
declare
out_of_stock exception;
begin
raise out_of_stock;
end;
/
ERROR at line 1:
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at line 4
begin
raise_application_error(-20000, 'Cheese is out of stock');
end;
/
ERROR at line 1:
ORA-20000: Cheese is out of stock
ORA-06512: at line 2
pragma exception_init(exception_name, error_code) lets you associate your own user-defined exception with a system error code. This can be useful from a programming perspective, but ultimately it doesn't add any value for the caller:
declare
invalid_day_of_month exception;
pragma exception_init(invalid_day_of_month, -1847);
d date;
begin
d := to_date('99-JAN-2020','DD-MON-YYYY');
exception
-- Pointless exception handler - just to demo raising a user-defined exception
when invalid_day_of_month then raise;
end;
/
ERROR at line 2:
ORA-01847: day of month must be between 1 and last day of month
ORA-06512: at line 10
ORA-06512: at line 7
Passing success/failure status via OUT parameters is usually a bad idea because the procedure will appear to have completed successfully, and the caller has to read the status to see whether it really succeeded or not.
I am sure my question has a simple theoretical answer but I cannot find it.
I have a procedure which accepts as parameter a NUMBER. It also have the VALUE_ERROR and OTHERS exceptions:
create or replace procedure test( p1 number) is
begin
null;
exception
when VALUE_ERROR then
RAISE_APPLICATION_ERROR(-20001, 'value_error');
when others then
RAISE_APPLICATION_ERROR(-20000, 'others');
end;
I am executing the procedure with a VARCHAR2 paramter:
execute test('a');
... an I expect that the error message displayed to be
ORA-20001 value_error
but, unfortunately, I got:
Error report - ORA-06502: PL/SQL: numeric or value error: character to
number conversion error ORA-06512: at line 1
06502. 00000 - "PL/SQL: numeric or value error%s"
*Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
*Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
Can anyone explain this, or share a link where it is explained why I do not receive expected error message?
Thank you very much,
As Nicholas mentioned you don't get your message because the exception is thrown not inside the procedure but before executing it.
Let's look at an example:
create or replace procedure test( p1 number) is
begin
null;
exception
when VALUE_ERROR then
RAISE_APPLICATION_ERROR(-20001, 'PROC value_error');
when others then
RAISE_APPLICATION_ERROR(-20000, 'PROC others');
end;
/
begin
test('a');
exception
when VALUE_ERROR then
RAISE_APPLICATION_ERROR(-20001, 'OUT value_error');
when others then
RAISE_APPLICATION_ERROR(-20000, 'OUT others');
end;
What happens here is that you're calling a procedure that requires number as parameter so Oracle tries conversion during execution of anonymous block. You can't see the message from the procedure because before entering the procedure the conversion exception is thrown.
Now let's see what happens if we change the procedure:
create or replace procedure test( p1 varchar2) is
param number;
begin
param := p1;
exception
when VALUE_ERROR then
RAISE_APPLICATION_ERROR(-20001, 'PROC value_error');
when others then
RAISE_APPLICATION_ERROR(-20000, 'PROC others');
end;
/
begin
test('a');
exception
when VALUE_ERROR then
RAISE_APPLICATION_ERROR(-20001, 'OUT value_error');
when others then
RAISE_APPLICATION_ERROR(-20000, 'OUT others');
end;
Or just:
begin
test('a');
end;
to see the error thrown in the procedure.
Now the procedure requires number within its body; when execution reaches that point it throws the conversion error, from within the procedure itself.
I store the error codes my stored procedures may throw (by calling raise_application_error) as constants. One of my procedures has to catch the error another one throws, and I am trying to do this with pragma exception_init.
It seems that it only accepts numeric literals (as it explicitly says so in the error message I get), but it would be great to be able not to hardwire the error codes I otherwise store in constants. Is there some workaround for this, so that I could achieve the same as if I wrote:
pragma exception_init(myException, pkg_constants.error_not_null);
You can't use the package constant, or any variable, in the pragma.
What you could do is define the exception itself and its associated pragma in your package:
create package pkg_constants as
MyException exception;
error_not_null constant pls_integer := -20001;
pragma exception_init(myException, -20001);
end pkg_constants;
/
You still have to repeat the error number, but at least only in the same file. You can then refer to that package-defined exception in a handler without having to redeclare it:
exception
when pkg_constants.MyException then
...
For example:
set serveroutput on
begin
raise_application_error(pkg_constants.error_not_null, 'Threw it');
exception
when pkg_constants.MyException then
dbms_output.put_line('Caught it');
raise;
end;
/
Error report -
ORA-20001: Threw it
ORA-06512: at line 6
Caught it
DECLARE
string_of_5_chars VARCHAR2(5);
BEGIN
BEGIN
string_of_5_chars := 'Steven';
EXCEPTION
WHEN value_error THEN
RAISE no_data_found;
WHEN no_data_found THEN
dbms_output.Put_line ('Inner block');
END;
EXCEPTION
WHEN no_data_found THEN
dbms_output.Put_line ('Outer block');
END;
Answer says that the output will be 'Outer block' , Can somebody explain why the inner block would not be executed ? What is the precedence of exceptions in oracle
DECLARE
string_of_5_chars VARCHAR2(5);
BEGIN
BEGIN
string_of_5_chars := 'Steven'; -- Varchar has a size of 5 defined above. So it will throw a value_error(due to size constraints) exception.
EXCEPTION
WHEN value_error THEN -- This exception block will handle the error thrown above.
RAISE no_data_found; -- It raises a no_data _found exception which by rule has to be handled in the outer exception block. So it goes to the outer exception block.
WHEN no_data_found THEN
dbms_output.Put_line ('Inner block');
END;
EXCEPTION
WHEN no_data_found THEN
dbms_output.Put_line ('Outer block'); -- Exception is handled here which causes it to print 'Outer Block'
END;
Read here for more information about nested exception blocks.
You should consider the exception block's WHEN clauses as being similar to a regular CASE statement. The first WHEN that matches the condition executes, and the following WHEN clauses in that exception handler are skipped.
Therefore the second WHEN clause in the inner exception block is not in the code execution path at all, and the outer exception block catches the no_data_found error raised by the first WHEN clause of the nested exception.
Exception propagation in this scenario is explained here: http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/errors.htm#LNPLS00706
As string_of_5_chars := 'Steven'; raises an value_error, the corresponding Exception block is entered.
Inside the Exception block the no_data_found Exception is raised. Due to the raising-part this exception is then handled by the exception-handling of the outer block.
For more information check http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/raise_statement.htm