I am getting the ORA-06503: PL/SQL: Function returned without value error in a pl/sql trigger code. I actualy want to do some specific exception handling only if this error occurs else do the regular exception handling in my code.
My question is how do I capture the specific ORA codes in exception blocks. Like If I want to add a if condition like
If(oracode = something) then ...
else ...
the SQLERRM gives the ora code with error message. how do I use this in IF condition ?
Need help with this
Thanks.
You are looking for SQLCODE - these are negative numbers when there is an error.
if SQLCODE = -6503 then ....
Related
Suppose I have a procedure as follows:
PROCEDURE proc_name (args)
IS
-- declarations
...
BEGIN
-- code
...
EXCEPTION
WHEN an_error THEN
--error handling code
....
WHEN another_error THEN
-- error handling code, identical to the one for an_error
...
WHEN others THEN
---generic error handling code`
....
END;
Ideally, I would like to be able to catch both an_error and another_error in the same WHEN clause, since their handling is identical.
Is this possible in Oracle? If not, what are other possibilities to avoid code duplication?
Yes you can.
You can use OR conditions between the exceptions so
EXCEPTION
WHEN an_exception
OR another_exception
THEN
handle it here;
END;
See The Docs for more details on exception handling.
Yes.
But not for OTHERS exception. It can not be merged with another exception.
I am running a method (the method name is sent by the end user) using dynamic PL/SQL (ex: EXECUTE IMMEDIATE).
When the method signature does not match the error ORA-06550 is raised (PLS-00306 is also mentioned in the stack).
I need to raise a custom message when the method signatures does not match with the required signature.
So I catch ORA-06550 inside the PL/SQL exception block and raise an error. Only to notice that ORA-06550 is raised for any invalid PL/SQL code (including method signature mismatch)
My Questions
What is the difference between ORA- type messages and PLS- types ones. Can't one catch PLS- type messages (ex: PLS-00306) like they do catch ORA- type ones (ex: ORA-06550). If possible how?
If not possible how to catch signature mismatches? (apart from running a query against USER_ARGUMENTS)
PLS-errors are PL/SQL compiler's compilation errors and can't be directly caught run-time as they are wrapped with ORA-errors.
If the compilation error is triggered by static PL/SQL the unit under compilation is created as invalid and execution of the unit triggers PLS-00905 (wrapped with ORA-06550).
If the compilation error is triggered by dynamic PL/SQL the unit under compilation is created without errors as dynamic PL/SQL is not checked during compilation. Instead the error is raised run-time when the unit is executed and can be caught but only ORA-code, not PLS-code. If you have do something based on PLS-code process the error stack string:
create or replace function get_custom_error(p_pls_code in varchar2) return varchar2 is
begin
return
case p_pls_code
when 'PLS-00201' then 'this is my custom error code'
else 'unknown PLS error code'
end;
end;
/
show errors
create or replace procedure foo is
plsql_compilation_error exception;
pragma exception_init(plsql_compilation_error, -6550);
v_a number;
begin
dbms_output.put_line('foo started');
execute immediate 'begin bar; end;';
dbms_output.put_line('foo ended normally');
exception
when plsql_compilation_error then
declare
v_pls_error_code constant varchar2(20) :=
regexp_substr(dbms_utility.format_error_stack,
'(PLS-[[:digit:]]+):', 1, 1, '', 1);
begin
dbms_output.put_line(get_custom_error(v_pls_error_code));
end;
end;
/
show errors
Execution example:
SQL> exec foo
foo started
this is my custom error code
PL/SQL procedure successfully completed.
SQL>
All Oracle error codes are listed and explained in Oracle Database Error Messages.
1) The difference between ORA and PLS is which engine raised the exception. Error on the top of error stack shows general error. Deeper errors provides more and more details. Like ORA-06550 happened because of PLS-00306
2) In any potentially dangerous place you should add BEGIN…EXCEPTION…END. To differentiate any ORA error you can declare exception in parent block and use PRAGMA directive to link it with error code.
begin
…
begin
…
execute immediate …
exception
when …
end;
…
end;
There are parameterized error messages in Oracle database. For example, there is 01919, 00000, "role '%s' does not exist" in oraus.msg.
If one issue some nonsense GRANT ... TO ... %s is substituted by this nonexistent privilege.
It is possible to raise exception -1919 and supply some string to %s?
Code:
not_system_privilege EXCEPTION;
PRAGMA EXCEPTION_INIT(not_system_privilege, -01919);
.......
RAISE not_system_privilege;
produces only ORA-01919: role '' does not exist message.
The purpose of user-defined exceptions is that we can trap specific exceptions in the exception section of our PL/SQL program and handle them elegantly. For instance, if we put some flesh around your code snippet....
create or replace grant_priv
( p_priv in varchar2
, p_grantee in varchar2 )
is
not_system_privilege EXCEPTION;
PRAGMA EXCEPTION_INIT(not_system_privilege, -01919);
begin
execute immediate 'grant '||p_priv||' to '||p_grantee;
exception
when not_system_privilege then
raise_application_error(-20000, p_priv||' is not a real privilege', true);
when others then
raise;
end;
We can put anything in the EXCEPTIONS section. Log the error in a table or file, raise alerts, whatever. It is good practice to propagate the exception upwards: only the toppermost layer of the callstack - the user-facing layer - shouldn't hurl exceptions.
An observation - it looks like you can use utl_lms.format_message for C-style printing - wish I'd known this earlier (as would have saved writing it). Seems to be Ora10 and above only.
begin
dbms_output.put_line(
utl_lms.format_message(
'A %s is here and a %s is there and a %s too','Giraffe','Lion','Spider'));
end;
I can't see any way to meet the OPs requirement - to RAISE a system-level exception and substitute in the right parameter.
However, if you can live with using a different exception number, you could write your own exception handling procedure that could
a) take in the serial of the required exception
b) use utl_lms.get_message to retrieve the text
c) use format_message to substitute in the parameters
d) raise a user defined exception using the generated text
The problem is that this would not work if your calling system expects an ORA-01919.
I want to know about error handling in PL/SQL. Can anyone help me to find brief description on this topic?
Every block can have an exception handler. Example:
DECLARE
/* declare your variables */
BEGIN
/*Here is your code */
EXCEPTION
WHEN NO_DATA_FOUND THEN
/* HAndle an error that gets raised when a query returns nothing */
WHEN TOO_MANY_ROWS THEN
/* HAndle the situation when too much data is returned such as with a select-into */
WHEN OTHERS THEN
/* Handle everything else*/
END;
This link will tell you more: http://download.oracle.com/docs/cd/B13789_01/appdev.101/b10807/07_errs.htm
That link will show you more detail than I did, as well as examples on how to create your own exception names.
One item that always trips me up is that if you have a function and you fail to return a value in the exception handler, an exception gets thrown in the calling function. Not a big deal but I always seem to forget that one.
The Oracle article referenced in the other answer is well worth reading.
A couple of extra things to throw in - catching a PL/SQL exception loses the error stack - i.e. the information about exactly which line raised the exception.
This can make it difficult to debug blocks of code that contain multiple places that could raise the same exception (i.e. if you have more than one SQL statement that could return NO_DATA_FOUND). One option here is to log the full error stack as part of your exception handler.
EXCEPTION
WHEN TOO_MANY_ROWS THEN
myLogger('Some useful information',DBMS_UTILITY.FORMAT_ERROR_STACK);
END;
If you do need to catch exceptions, keep your exception handling as local as possible to the point you want to catch, and only use WHEN OTHERS in the last resort.
You can also 'do something and re-raise the same exception'
EXCEPTION
WHEN TOO_MANY_ROWS THEN
closeSmtpConnection;
RAISE;
END;
One of the most useful features is the ability to name and catch Oracle SQL internal exceptions.
DECLARE
recompile_failed EXCEPTION;
PRAGMA EXCEPTION_INIT (recompile_failed,-24344);
BEGIN
. . . . . .
EXCEPTION
WHEN recompile_failed THEN
emailErrors(pObjectType,pObjectName);
END;
The flipside to this is the ability to raise user defined 'SQL' exceptions
RAISE_APPLICATION_ERROR(-20001,'my text')
This is the only way to propagate user defined text to a calling application, as user-defined pl/sql exceptions do not cross the 'scope' boundary.
Unfortunately, despite the documentation saying that the range -20000 to -20999 is available for user-defined exceptions, some of the Oracle extension packages use these serials, so you cannot depend on serial alone to identify an error in the calling language.
(Most people tend to wrap RAISE_APPLICATION_ERROR in other code to also log the error, and often to derive the error text from a table)
One trick I've found useful is to create a package with 'stateful' variables in the package body, and simple setter and getter functions. Unlike database updates, information in packages is NOT rolled back on error.
At the point of error, set information in your package, then retrieve it using getters in your calling language, to construct a 'native' exception.
As for user-defined pl/sql exceptions - these can be useful in local code, but in many cases they can be avoided by using a different control structure (i.e. avoid using them as an alternative GOTO).
Creating global exceptions on package headers, to specify the possible exceptions a package may return seems like a good idea, but the end result is that your calling code ends up with having to handle every potential exception that could be cast in any of the underlying packages.
Having gone down this route myself in the past, I would now recommend against it - make packages self-contained and either use RAISE_APPLICATION_ERROR or pass back errors as text.
In a stored procedure I have used to;
raise_application_error (-20010, 'My Message');
to raise a custom error in a certain situation. What I am trying to do is when I make my JDBC call from java, to be able to identify this error as not just being a SQLException so that I can handle it differently. I though I could identify it by the errorCode, but that seems to always be 17062 and not -20010.
Is there another way to do this, or am I missing something?
you should get 20010 as your errorCode. the ORA-17062 is an error for invalid ref cursors. Are you sure the procedure you are calling throws the custom error ?