oracle exception not going to exception block - oracle

I need to update some code which uses dynamic sql and potentially could have duplicate column names in the columns of the insert statement.
So I wanted to handle this, ORA-00957: Duplicate Column name. This error does not get handled by the most generic "when others" in the exception block. If I make it test a unique constraint violation it does.
Following some test code:
create table animal (id number , animal_type number,
animal_name varchar2(20), constraint id primary key(id));
-----------------------------------------------------
begin
for i in 1.. 100 loop
insert into animal(id, animal_type, animal_name)
values(i,floor(dbms_random.value(1,30)),'animal'||i);
end loop;
end;
-----------------------------------------------------
DECLARE
-- e_duplicate_column exception;
-- pragma exception_init(e_duplicate_column,-957);
BEGIN
insert into animal(id, animal_name, animal_name)
values(1000003, 'animal 1000003', 'animal 1000003');
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLCODE);
dbms_output.put_line(SQLERRM);
END;
I was trying to get the codes here as the pragma wasn't working(i.e. arriving) either. But that's not happening if it doesn't even get to "when others".
Any insights are appreciated.
Cheers, Robbert
PS oracle 12C, tried on sqldeveloper and toad

Your test code does not use dynamic SQL, which is required to generate an ORA-00957 error. Without dynamic SQL, Oracle will throw the ORA-00957 when it compiles your block, which I think you are misinterpreting as Oracle actually running you block and skipping the exception handler.
Try this instead as a test (make sure you have DBMS output enabled in your client!):
DECLARE
-- e_duplicate_column exception;
-- pragma exception_init(e_duplicate_column,-957);
BEGIN
execute immediate q'[insert into animal(id, animal_name, animal_name) values(1000003, 'animal 1000003', 'animal 1000003')]';
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLCODE);
dbms_output.put_line(SQLERRM);
END;
-957
ORA-00957: duplicate column name

Related

PL/SQL : Ignoring -942 EXCPETION issues - still bombs on PACKAGE Compilation

I have a Procedure within a Package that I create a "Temporary" table for processing. I wrote code to IGNORE the -942 error because at the end of the Procedure I drop the table. Therefore when it runs again, the table wouldn't exist and it needs to ignore that error.
However, when I compile the code (without the table present) it still bombs on me even with the EXCEPTION logic claiming the "table does not exist" which is true, but I don't care.
What am I doing wrong?
--Temp Table Setup
V_TEMP_COUNT INT;
NO_SUCH_TABLE EXCEPTION;
PRAGMA EXCEPTION_INIT (NO_SUCH_TABLE, -942);
--Declare Record Types
REC_P170201 CUR_P170201%ROWTYPE;
BEGIN --[SP_LOAD_A_DEPARTMENT_PVSS]
------------------------------------------------------------------------------------------
--PART P17.01 INITIALIZE --
------------------------------------------------------------------------------------------
BEGIN
SELECT COUNT (*) INTO V_TEMP_COUNT
FROM USER_TABLES
WHERE TABLE_NAME = UPPER('F_DEPARTMENT_ADT');
EXCEPTION
WHEN NO_SUCH_TABLE THEN
NULL;
WHEN OTHERS THEN
RAISE;
END;
-- other stuff
END SP_LOAD_A_DEPARTMENT_PVSS;
The following block of code will not raise the NO_SUCH_TABLE error when there is no table named F_DEPARTMENT_ADT
BEGIN
SELECT COUNT (*) INTO V_TEMP_COUNT
FROM USER_TABLES
WHERE TABLE_NAME = UPPER('F_DEPARTMENT_ADT');
EXCEPTION
WHEN NO_SUCH_TABLE THEN
NULL;
WHEN OTHERS THEN
RAISE;
END;
That is because the query is asking the view USER_TABLES if there is a row whose table_name column value is UPPER('F_DEPARTMENT_DAT'). Instead of a NO_SUCH_TABLE error, the error you will get is a no data found err (ORA-1403).
You cannot catch compilation errors. One way to handle the none existence of a table is to perform the SELECT-Statement as dynamic sql, so it does get compiled on runtime:
EXECUTE IMMEDIATE 'SELECT COUNT (*) FROM USER_TABLES WHERE TABLE_NAME = UPPER(''F_DEPARTMENT_ADT'')'
INTO V_TEMP_COUNT;
But I think the code you posted is not the one that throws your error at compile time. It might be the declaration of REC_P170201. So in this case I would recommend you, to create your own record type with only the columns you need in your procedure and then just select the columns you need in the dynamic sql.
SELECT COUNT (*) INTO V_TEMP_COUNT
FROM USER_TABLES
WHERE TABLE_NAME = UPPER('F_DEPARTMENT_ADT');
Is not going to fail if F_DEPARTMENT_ADT does not exist. It will either return a value into V_TEMP_COUNT of 0 or 1. You will can use that to make decisions in the rest of your code.
If you need your code to actually use your table then it will need to be done in dynamic SQL so that the compilation of your PL/SQL is not dependent on the compilation of your SQL (which will sometimes fail).
Saying that, I 100% agree with EdStevens: you're after a global temporary table here.

Trigger not working for stopping table insert

I am using the following code for stopping null value insert into table using trigger. But when I pass null value, the inserting is happening fine. Any idea what am I doing wrong here?
create table test
(col1 number,
col2 varchar2(40)
)
create or replace trigger test_trg
after insert on test
for each row
declare
excp exception;
pragma autonomous_transaction;
begin
if :new.col2 is null then
RAISE excp;
end if;
exception
when excp then
dbms_output.put_line('error');
rollback;
end;
(Please note, I do accept that using a not null or a check constraint on the col2 is a better solution. I just want to find out the reason behind the error in this seemingly correct code)
Don't rollback in trigger, just re-raise excpetion after logging it:
create or replace trigger test_trg
after insert on test
for each row
declare
excp exception;
pragma autonomous_transaction;
begin
if :new.col2 is null then
RAISE excp;
end if;
exception
when excp then
dbms_output.put_line('error');
raise; -- propagate error
end;
When you put "exception ... end;" block in code you say to PL/SQL that managing consequences of this error is on your responsibility. So, if you don't raise any error from a code which handles original error, for PL/SQL it means that all actions regarding this error already done in your code, all went OK and record must be inserted.
You can try it in this SQLFiddle.
you have to define the trigger as BEFORE INSERT to fire before the insert is executed, remove the pragma autonomouse_transaction and the rollback (they have no sense here, because you do not any DML), then reraise the exception in the exception handler

PLSQL: BEFORE INSERT TRIGGER (check value in column from other table before allowing insert)

I've made a simple DVD store database. The DVD table has a column "status" which can be either 'FOR_RENT','FOR_SALE','RENTED',or 'SOLD'. I want to write a trigger to block any insertions into my RENTALS table if the status column in the DVD table is not set to 'FOR_RENT'.
Much of the documents I've looked at generally don't show example using values from two different tables so I'm a bit flummaxed.
This is what I believe has been my best attempt so far:
CREATE OR REPLACE TRIGGER RENTAL_UNAVAILABLE
BEFORE INSERT ON RENTAL;
FOR EACH ROW
WHEN (DVD.STATUS != 'FOR_RENT')
DECLARE
dvd_rented EXCEPTION;
PRAGMA EXCEPTION_INIT( dvd_rented, -20001 );
BEGIN
RAISE dvd_rented;
EXCEPTION
WHEN dvd_rented THEN
RAISE_APPLICATION_ERROR(-20001,'DVD has been rented');
END;
/
I'm getting this error:
ORA-00911: invalid character
Try this - I have not complied the code, but should be good. In case you see any compilation issues let me know and post schema on sqlfiddle.com
CREATE OR REPLACE TRIGGER rental_unavailable
BEFORE INSERT
ON rental
FOR EACH ROW
DECLARE
dvd_rented EXCEPTION;
PRAGMA EXCEPTION_INIT (dvd_rented, -20001);
n_count NUMBER (1);
BEGIN
SELECT COUNT (*)
INTO n_count
FROM dvd
WHERE dvd_id = :NEW.dvd_id AND dvd.status = 'FOR_RENT' AND ROWNUM < 2;
IF n_count > 0
THEN
RAISE dvd_rented;
END IF;
EXCEPTION
WHEN dvd_rented
THEN
raise_application_error (-20001, 'DVD has been rented');
END;

Raise parent key integrity constraint in procedure for each column

I have the following code in a package which inserts data into table.
I am able to get parent key not found exception. How can I specifically get constraint violated message for each column? E.g. if proj_id is violated then raise exception, if proj_code is violated, then raise another exception.
PROCEDURE add_project(
p_proj_id project.proj_id%TYPE,
p_proj_desc project.proj_desc%TYPE,
p_proj_code project.proj_code%TYPE,
p_proj_date project.proj_date%TYPE
)
IS
parent_not_found exception;
pragma exception_init(parent_not_found, -2291);
BEGIN
INSERT
INTO projects (proj_id,proj_desc,proj_code,proj_date) values
(p_proj_id,p_proj_desc,p_proj_code,p_proj_date);
exception
when parent_not_found then
raise_application_error(-20001,'Invalid');
END;
Take a look at EXCEPTION_INIT Pragma.
DECLARE
l_parentnotfound exception;
l_res integer;
PRAGMA EXCEPTION_INIT(l_parentnotfound, -2291);
BEGIN
-- check if the parent key exists
select 1 into l_res from codes where code = proj_code;
-- if not, raise exception
if l_res <> 1 then
raise l_parentnotfound;
end if;
INSERT INTO projects (proj_id,proj_desc,proj_code,proj_date) values (p_proj_id,p_proj_desc,p_proj_code,p_proj_date);
EXCEPTION WHEN l_parentnotfound THEN
-- handle the error
END;
Or you can use WHEN OTHERS and look for the SQLCODE.
EDIT:
Note that you are not forced to manually check that the parent key exists to raise the exception, you can stay with :
DECLARE
l_parentnotfound exception;
l_res integer;
PRAGMA EXCEPTION_INIT(l_parentnotfound, -2291);
BEGIN
INSERT INTO projects (proj_id,proj_desc,proj_code,proj_date) values (p_proj_id,p_proj_desc,p_proj_code,p_proj_date);
EXCEPTION WHEN l_parentnotfound THEN
-- handle the error
END;
But if you want to be able to get violated constraint name easily, it can be useful to raise exception manually for each column. Also you can try to get the constraint name using USER_CONSTRAINTS and USER_CONS_COLUMNS.
Another way to get the violated constraint name is to parse the SQLERRM error message.
try
create PROCEDURE add_project(p_proj_id project.proj_id%TYPE,
p_proj_desc project.proj_desc%TYPE,
p_proj_code project.proj_code%TYPE,
p_proj_date project.proj_date%TYPE) IS
BEGIN
INSERT INTO projects
(proj_id, proj_desc, proj_code, proj_date)
values
(p_proj_id, p_proj_desc, p_proj_code, p_proj_date);
--add this
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;

Handle ORACLE Exceptions

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

Resources