ORA-06510: PL/SQL: unhandled user-defined exception [Oracle] - oracle

I'm relatively new to Oracle so forgive me for my lack of knowledge. Whenever this trigger is fired I keep getting an error stating that I have an unhandled user-defined exception. Elsewhere in my functions and procedures I have declared and raised my user-defined exactly as this but in this case is doesn't work. I know it's probably something trivial and obvious but as I said I'm fairly new to Oracle so please forgive me.
CREATE OR REPLACE TRIGGER PROGRAMME_BI
BEFORE INSERT ON PROGRAMME
DECLARE
v_run_time programme.run_time%TYPE;
INVALID_DURATION EXCEPTION;
BEGIN
IF v_run_time > 5 THEN
DBMS_OUTPUT.PUT_LINE('Program duration is valid');
COMMIT;
ELSE
RAISE INVALID_DURATION;
END IF;
EXCEPTION
WHEN INVALID_DURATION THEN
RAISE_APPLICATION_ERROR(-20001,'Program duration is not long enough');
ROLLBACK WORK;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||SQLERRM);
END;
UPDATE
I have updated the line after the exception is raised so it doesn't give me the unhandled user-defined exception error anymore. However it still does not work as intended. Whenever I enter in a program duration greater than 5 I get the following in the DBMS output window.
-20001ORA-20001: Program duration is not long enough
ORA-06512: at "DT2113A.PROGRAMME_BI", line 13
ORA-04088: error during execution of trigger 'DT2113A.PROGRAMME_BI'
Program not added

you have to assign value to v_run_time Kindly try the below
CREATE OR REPLACE TRIGGER PROGRAMME_BI
BEFORE INSERT ON PROGRAMME
FOR EACH ROW
DECLARE
v_run_time programme.run_time%TYPE:=:new.run_time;
INVALID_DURATION EXCEPTION;
BEGIN
IF v_run_time > 5 THEN
DBMS_OUTPUT.PUT_LINE('Program duration is valid');
COMMIT;
ELSE
RAISE INVALID_DURATION;
END IF;
EXCEPTION
WHEN INVALID_DURATION THEN
RAISE_APPLICATION_ERROR(-20001,'Program duration is not long enough');
ROLLBACK WORK;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||SQLERRM);
END;

Related

Why is code in PLSQL not executing after "exception" part?

So I made a bug in which I didn't put execute immediate inside nested begin-end block so my code didn't work. So basically I had
begin
execute immediate 'select * from sales';
exception when others then null;
dbms_output.put_line(123);
end;
Dbms_output did not print "123" and I figured out I need to put execute immediate inside begin-end. I want to be sure, so my question is why is code not executing after exception part even though exception is not raised?
why is code not executing after exception part even though exception is not raised?
The reason is very simple - dbms_output.put_line in the question is not in "after exception part".
Properly indented code is equivalent to:
begin
execute immediate 'select * from dual';
exception when others then
null;
dbms_output.put_line(123);
end;
/
Exception block is everything between EXCEPTIONS and END; and will be executed if an exception occurs.
A couple of things in play here - parsing and execution.
If the table does not exist, then the statement cannot be parsed, and hence we'll get an exception immediately.
SQL> begin
2 execute immediate 'select * from xxxx';
3 end;
4 /
begin
*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at line 2
However, if the table DOES exist then the parse will be fine. Because you never specified an INTO that is all we do. We never needed to execute and commence the fetch phase and thus no error occurred. An easy to way to see that we never executed the statement is with something like
SQL> begin
2 execute immediate 'select 1/count(*) from dual where 1=2';
3 end;
4 /
PL/SQL procedure successfully completed.
If we had executed, then we'd expect a divide by zero error to come out. The moment we see an INTO, then we'll need to fetch (which will require an execution).

PL/SQL Continue after exception raised

I've got simple trigger with exception handling. My problem is how continue with application when user get error message.
CREATE OR REPLACE TRIGGER "AR_CHECK"
BEFORE INSERT ON TABLE
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
DECLARE
v_check number;
cursor c_ar_check is
select ar_no
from name_view
where name_id = :new.bill_to_name_id
and name_type in ('TRAVEL_AGENT','COMPANY');
begin
open c_ar_check;
fetch c_ar_check into v_check;
close c_ar_check;
if v_check is null then
raise_application_error(-20101, 'ERROR - NUMBER MISSING');
end if;
end;
With code above I've got error message but user cannot continue with next step.
Is it possible to get user warning about NULL value but with possibility to go on?
With raise_application_error, no. It will terminate execution.
But, if you substitute it with something else - a trivial dbms_output.put_line would do in testing phase, while some logging process - such as calling a(n autonomous transaction) procedure - might be a better option in production.
If you choose dbms_output.put_line, note that your won't see any message until the procedure is finished.

A SQL exception was caught. The error was: ORA-04098: trigger is invalid and failed re-validation

I have created a trigger with the below code
create or replace trigger DTE_SAVE_ORIGINAL_VAL
after update
on attrvaldesc
FOR Each row
when (new.field2 is null)
Declare
attrvaloriginal attrval.attrval_id%TYPE;
attrval_id attrval.attrval_id%TYPE;
language_id attrvaldesc.language_id%type;
storeent_id attrval.storeent_id%type;
PRAGMA AUTONOMOUS_TRANSACTION;
Begin
Dbms_Output.Put_Line(:OLD.attrval_id);
select attrval_id into attrvaloriginal from attrval where identifier = (select identifier||'_original' from attrval where attrval_id= :OLD.attrval_id and storeent_id=10051) and storeent_id=10051;
if (attrvaloriginal > 0) then
Dbms_Output.Put_Line(attrvaloriginal);
Dbms_Output.Put_Line(:NEW.value);
delete from attrval where attrval_id = attrvaloriginal and storeent_id=10051;
commit;
END IF;
End;
The trigger has compiled and when i trigger a job which updates attrvaldesc table, I'm facing the below exception
Exception message:
A SQL exception was caught. The error was: ORA-04098: trigger 'WCS_ADMIN_HFI.DTE_SAVE_ORIGINAL_VAL' is invalid and failed re-validation
Stack trace:
com.ibm.commerce.foundation.dataload.exception.DataLoadSQLException: A SQL exception was caught. The error was: ORA-04098: trigger 'WCS_ADMIN_HFI.DTE_SAVE_ORIGINAL_VAL' is invalid and failed re-validation
To check if any errors in my trigger I did a
SHOW ERRORS TRIGGER DTE_SAVE_ORIGINAL_VAL;
I returned the below
18/1 PLS-00103: Encountered the symbol "DROP"
The code you've shown doesn't include the word 'drop'. But the error message also refers to line 18. In a trigger a PLS error only refers to the PL/SQL section, starting with declare or begin. Your PL/SQL section only has 16 lines, from declare to end;. This indicates the problem is not quite in what you've shown.
From that we can deduce that you've created your trigger as part of a script, and the next statement was dropping an object:
create or replace trigger DTE_SAVE_ORIGINAL_VAL
...
End;
drop ...
Because it's PL/SQL the trigger creation needs to be submitted with a / character. At the moment everything after your actual trigger, down to the next time a / appears in your script (or the end of the script, potentially), is being accidentally included as part of the trigger definition, which means it's including things that are not valid PL/SQL. From the error that includes a drop, but it may also include other statements, dropping, creating or altering any number of objects.
So you need to add a slash after the trigger in your script:
create or replace trigger DTE_SAVE_ORIGINAL_VAL
...
End;
/
drop ...
You can just re-run the trigger statement on its own, but bear in mind that whatever followed it - everything that was accidentally treated as part of the trigger - was not executed at all, so you may be missing other objects, or have them built differently to how you expect (if the script was supposed to drop and then recreate objects).
You might want to fix and then re-run the whole script, as long as you haven't added any data that would destroy - which is likely if you're now updating data. If that isn't a safe thing to do then see what else wasn't done, and execute those parts manually too, again watching out for potential data loss.

Function resumes execution after exception in subprogram

I am raising an exception in a subprogram, and I'm expecting to see the calling function halt execution at this point. However, the calling function continues processing as if nothing happened, and I don't understand why.
My function looks something like this:
FUNCTION getFooCursor (i_blah IN VARCHAR)
RETURN t_ref_cursor
IS
v_sum_variable NUMBER;
BEGIN
--lookup number
v_sum_variable := getNumber (i_blah);
--call function that raises NO_DATA_FOUND exception
doRaiseException();
--the exception handler is only supposed to catch for this block
BEGIN
--do stuff and end up with a cursor
RETURN barCursor(v_sum_variable);
EXCEPTION
WHEN OTHERS THEN
--set some variables
END
END;
Let's say doRaiseException() looks like this:
PROCEDURE doRaiseException ()
IS
BEGIN
RAISE NO_DATA_FOUND;
END;
When I debug this function in TOAD, it helpfully informs me that the NO_DATA_FOUND exception has been raised. However, it then immediately carries on to execute the next line (where barCursor() is called) and the function finishes as if nothing ever went wrong.
I have tried replacing doRaiseException(); directly with RAISE NO_DATA_FOUND; for testing purposes (it actually does more than that) and this stops execution within getFooCursor() but whatever SQL calls it again completely ignores the exception.
Is this just how exceptions work in PL/SQL? Don't they bubble up as they do in Java or C#? Perhaps I am missing something crucial about exceptions in Oracle. How do I get an exception to bubble up to the host?
Here is my Oracle version (as returned from v$version):
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi
PL/SQL Release 10.2.0.5.0 - Production
CORE 10.2.0.5.0 Production
TNS for HPUX: Version 10.2.0.5.0 - Production
NLSRTL Version 10.2.0.5.0 - Production
Your understanding of exceptions is correct. However, this is one notable exception to how exceptions work: NO_DATA_FOUND is silently ignored in a SQL context. This is a "feature", because this is how Oracle tells other processes that there is no more data to read.
For custom exceptions, you will probably need to catch NO_DATA_FOUND and raise it as different exception. This is usually a horrible way to handle exceptions but there is no good alternative here.
SQL> create or replace function function1 return number is
2 begin
3 raise no_data_found;
4 return 1;
5 end;
6 /
Function created.
SQL> select function1 from dual;
FUNCTION1
----------
1 row selected.
SQL> create or replace function function2 return number is
2 begin
3 raise no_data_found;
4 return 1;
5 exception when no_data_found then
6 raise_application_error(-20000, 'NO_DATA_FOUND raised');
7 end;
8 /
Function created.
SQL> select function2 from dual;
select function2 from dual
*
ERROR at line 1:
ORA-20000: NO_DATA_FOUND raised
ORA-06512: at "JHELLER.FUNCTION2", line 6
Exceptions work as you suppose and "bubble up", so you must be catching it somewhere.
That's what's happening... you're catching every exception, which isn't the best practice. You can either ensure you only catch a specific exception if you define one yourself. However, that doesn't seem to be what you want to do here. You want to re-raise only a single exception.
So, you could define a custom exception in a separate package, raise that in your sub-program and then do something like this in your calling block:
begin
RaiseException;
exception
when my_exception_package.my_exception then
raise;
when others then
DoSomethingElse;
end;
That way you catch the exceptions you want to raise and then re-raise them. If the exception is different then you continue with your current programme flow.

Getting some extra exceptions and messages on screen when my triggers gets fired

This is my code:
CREATE OR REPLACE TRIGGER unsuccessful_logins
AFTER INSERT OR UPDATE
ON temp_logins
for each row
DECLARE
CURSOR c_unsuccessful_attempts
IS
SELECT * from temp_attempts
and user_id= :new.user_id;
max_fails EXCEPTION;
BEGIN
FOR r_unsuccessful_attempts in c_unsuccessful_attempts
LOOP
if(:new.user_id = r_unsuccessful_attempts.user_id) then
if (r_unsuccessful_attempts.locked = 'Y') then
raise max_fails;
end if;
else
null;
end if;
END LOOP;
EXCEPTION
WHEN max_fails THEN
RAISE_APPLICATION_ERROR (-20300,'User '''||:new.login_name||''' has reached maximum failed logins. Please contact your system administrator ');
END unsuccessful_logins;
The error I am getting in my oracle apps screen is:
APP-01564: ORACLE error 20300 in fdssgn
cause: fdssgn failed due to ORA-20300: You have reached maximum failed logins. Please contact your system administrator.
ORA-06512: at "APPS.UNSUCCESSFUL_LOGINS",line 24
ORA-04088: error during excution of trigger 'APPS.UNSUCCESSFUL_LOGINS'.
The SQL statement being executed at the time of the error was:
INSERT INTO TEMP_LOGINS (USER_ID, ATTEMPT_TIME,TERMINAL_ID,LOGIN_NAME)
values(:user_id, sysdate,:erminal_id,:login_name)
I just want to display ORA-20300: You have reached maximum failed logins. Please contact your system administrator part.
And want to omit:
ORA-06512: at "APPS.UNSUCCESSFUL_LOGINS",line 24
ORA-04088: error during excution of trigger 'APPS.UNSUCCESSFUL_LOGINS'.
The SQL statement being executed at the time of the error was:
INSERT INTO TEMP_LOGINS (USER_ID, ATTEMPT_TIME,TERMINAL_ID,LOGIN_NAME)
values(:user_id, sysdate,:erminal_id,:login_name)
How can I get rid off these extra messages on the screen?
I'm not sure exactly what you mean by 'oracle apps', but this link may help; it has a section on exception handling.
As I suggested in an earlier comment, I suspect you need something in your application code to catch and gracefully handle the exception raised by the trigger, so some kind of wrapper around the insert statement. The link is specifically talking about handling an exception in Forms, which (as is probably quite clear) I'm not familiar with, but the principal is likely to be the same if you're using something related.
Adapting their example slightly, something like this might fit what I think you're trying to do:
DECLARE
too_many_attempts EXCEPTION;
PRAGMA EXCEPTION_INIT(too_many_attempts, -20300);
BEGIN
INSERT INTO TEMP_LOGINS (USER_ID, ATTEMPT_TIME,TERMINAL_ID,LOGIN_NAME)
values(:user_id, sysdate,:erminal_id,:login_name);
EXCEPTION
WHEN too_many_attempts THEN
fnd_message.set_string(SQLERRM);
fnd_message.error;
RAISE FORM_TRIGGER_FAILURE;
END;
The simple answer is, you can not omit output from RAISE_APPLICATION_ERROR. You could consider using dbms_output.put_line to provide a single message.
...
WHEN max_fails THEN
dbms_output.put_line('User Message');

Resources