I am trying to drop the queue using following command:
EXECUTE DBMS_AQADM.DROP_QUEUE (queue_name => 'ORDVAL_QUEUE');
It is working fine but i want to put a check if queue does not exist and i execute above command thn it should not throw an error or exception.
I m using this but din't got my target :
BEGIN
EXECUTE IMMEDIATE 'DBMS_AQADM.DROP_QUEUE (queue_name => "ORDVAL_QUEUE")';
EXCEPTION
WHEN OTHERS THEN
null;
END;
It executes fine but does not drop queue.
I haven't used queues before, but this should help:
Add a BEGIN and END to the execute immediate, to use dynamic PL/SQL instead of dynamic SQL.
Use two single quotes instead of a double quote.
Catch specific exceptions when possible, avoid OTHERS. This was catching and ignoring unexpected exceptions.
Not shown below, but perhaps it would be better to check for the existence of the queue in ALL_QUEUES instead?
DECLARE
QUEUE_DOES_NOT_EXIST EXCEPTION;
PRAGMA EXCEPTION_INIT(QUEUE_DOES_NOT_EXIST, -24010);
BEGIN
EXECUTE IMMEDIATE
'BEGIN DBMS_AQADM.DROP_QUEUE (queue_name => ''ORDVAL_QUEUE''); END;';
EXCEPTION WHEN queue_does_not_exist then
dbms_output.put_line('Test to see if exception was thrown');
END;
/
Related
I'm creating a process in Oracle Apex 5.0. Please help me to get rid some duplicate error codes.
I've multiple conditions where error needs to be thrown. But at the end of the block when I write Exception block with sqlerrm it throws error code two times.
begin
-----------------------------
-----some code statements----
-----------------------------
if (<condition 1>) then
-----------------
----some code----
-----------------
elsif(<condition 2>) then
raise_application_error(-20001, '----statement1----');
elseif(<condition 3>) then
raise_application_error(-20002), '----statement2----');
end if;
exception
when others then
raise_application_error(-20003, SQLERM);
end;
Now, if any error occurs because of those IF statements then result will look like
ORA-20001: ORA-20003: ----statement1----.
But I need to show like, for example
ORA-20001: ----statement1----
How can I get it? Please help me to find what should I do here.
RAISE_APPLICATION_ERROR throws a bespoke error. But like any other exception that our application might hurl it is trapped by the local exception handler.
Your exception handler is raising a new bespoke exception for any and all errors. Don't do this. You can easily fix your problem by removing the exception block. All exceptions will be propagated up the calling stack without any modification.
begin
-----------------------------
-----some code statements----
-----------------------------
if (<condition 1>) then
-----------------
----some code----
-----------------
elsif(<condition 2>) then
raise_application_error(-20001, '----statement1----');
elseif(<condition 3>) then
raise_application_error(-20002), '----statement2----');
end if;
end;
Alternatively, you could employ user-defined exceptions.
declare
x_condition2 exception;
x_condition3 exception;
begin
-----------------------------
-----some code statements----
-----------------------------
if (<condition 1>) then
-----------------
----some code----
-----------------
elsif(<condition 2>) then
raise x_condition2;
elseif(<condition 3>) then
raise x_condition3;
end if;
exception
when x_condition2 then
raise_application_error(-20001, '----statement1----');
when x_condition3 then
raise_application_error(-20002, '----statement2----');
end;
You still needn't bother with WHEN OTHERS unless you have some specific processing you want to apply to all errors (such as logging them). There is no value in just re-raising an exception in the handler section because propagation happens by default.
#Deep asked
cant we make both exceptions?
Yes we can do this:
declare
x_condition2 exception;
PRAGMA EXCEPTION_INIT(x_condition2,-20001);
x_condition3 exception;
PRAGMA EXCEPTION_INIT(x_condition3,-20002);
….
Declaring an exception creates a bespoke exception. PRAGMA EXCEPTION_INIT associates a bespoke error number with that exception. I wouldn't bother doing this in an anonymous block, because we don't get much value from it. We would still need to execute raise_application_error to return our tailored error messages.
Where pragma exception_init becomes really useful is when we are passing exceptions between program units. Exceptions which need to be handled by calling programs should be declared in package specs. Using pragma exception_init means that we can identify errors using sqlcode which can be helpful for tasks such as looking up standard error messages from a table, providing user help text, etc.
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 working on a total rewrite of a PL/SQL program which is an EBS inbound interface to a third party system. In this process we receive input from the 3rd party system which is loaded into a table, and the program loops through the table to call EBS APIs for modifying and creating records. The business logic is very complicated and the code has spiraled out of control which is the reason for the rewrite.
Before calling some of the EBS APIs, we need to validate the incoming data against what is in the Oracle EBS system. The current code has several (20+) procedures to check various pieces of incoming data. Each of these procedures returns a status and a message. Then there is one main procedure which calls all of these validation procedures, and after each procedure call it looks at the status and message - the main procedure is basically a sea of if-else statements and it is extremely cumbersome to follow.
I'm wondering if there's a more suitable practice for performing this quantity of validations so that the code is easier to read and maintain. I have considered making all of the procedures into functions that return boolean values but then I still have the problem of tons of if-else statements in the main calling procedure. I'm just looking for other ideas at this point, the ultimate goal is to improve maintainability of this program.
Thanks in advance
You can't escape the fact that if you have 20 things you have to evaluate you need to have 20 check points in a one way or another.
Your problem statement is very broad but below is one example how I have implemented the same pattern succesfully. The main idea is that the checks (or validation) do not pollute that main business logic but are clearly separated so the main business logic is easy to follow. PL/SQL is sometimes a bit verbose language - here the verbosity goes into exception handling.
Note that in the example I have made some assumptions that might not hold in you specific case.
Validation package:
--
-- NOTE: PL/SQL look alike pseudo code - won't compile
--
-- br = business rule
create or replace package body so46_br is
-- different exceptions required only if each case needs to be identified
-- later in exception handling
err_br_1 constant pls_integer := -20001;
ex_br_1 exception;
pragma exception_init(ex_br_1, -20001);
-- ...
err_br_20 constant pls_integer := -20020;
ex_br_20 exception;
pragma exception_init(ex_br_1, -20020);
procedure assert_br_1(/* input params */) is
v_fail boolean := false;
v_msg varchar2(2000);
begin
-- validate the business rule #1
if v_fail then
v_msg := 'Construct detailed reason why the validation failed.';
raise_application_error(err_br_1, v_msg, true);
end if;
end;
-- ...
procedure assert_br_20(/* input params */) is
v_fail boolean := false;
v_msg varchar2(2000);
begin
-- validate the business rule #20
if v_fail then
v_msg := 'Construct detailed reason why the validation failed.';
raise_application_error(err_br_20, v_msg, true);
end if;
end;
end;
Business logic package:
--
-- NOTE: PL/SQL look alike pseudo code - won't compile
--
-- bl = business logic
create or replace package body so46_bl is
procedure main(/* input params */) is
begin
-- #1 validate input params/business rules
-- assumes we can quit if any validation fails
so46_br.assert_br_1(/* input params */);
-- ...
so46_br.assert_br_20(/* input params */);
-- #2 do the other business logic things
exception
-- assumes each validation failure needs to be identifiable
when so46_br.ex_br_1 then
so46_log.log_br_1(dbms_utility.format_error_stack ||
dbms_utility.format_error_backtrace);
raise;
-- ...
when so46_br.ex_br_20 then
so46_log.log_br_20(dbms_utility.format_error_stack ||
dbms_utility.format_error_backtrace);
raise;
end;
end;
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.