SQL> Exec Dbms_Scheduler.stop_job('US_ALERT',true);
begin Dbms_Scheduler.stop_job('US_ALERT',true); end;
ORA-27466: internal scheduler error: 1870
ORA-06512: at "SYS.DBMS_ISCHED", line 227
ORA-06512: at "SYS.DBMS_SCHEDULER", line 674
ORA-06512: at line 1
Does anyone has any idea of what's going wrong here ?
Database : Oracle
Version : 12c
This error is caused by the stack being unwound by unhandled exceptions in pl/SQL code. Most likely the scheduler is executing a procedure with some bad code in it. (See http://www.techonthenet.com/oracle/errors/ora06512.php)
The first thing to do is drop the job
BEGIN
DBMS_SCHEDULER.DROP_JOB('myjob1');
END;
/
Then start investigating your stored procedure(s) and add in some exception handling.
For example you might have some pl/sql code as follows
DECLARE pe_ratio NUMBER(3,1);
BEGIN
SELECT price / earnings INTO pe_ratio FROM stocks WHERE symbol = 'XYZ'; -- might cause division-by-zero error
INSERT INTO stats (symbol, ratio) VALUES ('XYZ', pe_ratio); COMMIT;
End;
If this was called by your job it could result in a ora 06512. (You probably will need to add in some logging/traces into to your pl/SQL to narrow this down, the line numbers in the error messages you reported may also help)
Replace it with
DECLARE pe_ratio NUMBER(3,1);
BEGIN
SELECT price / earnings INTO pe_ratio FROM stocks WHERE symbol = 'XYZ'; -- might cause division-by-zero error
INSERT INTO stats (symbol, ratio) VALUES ('XYZ', pe_ratio);
COMMIT;
EXCEPTION -- exception handlers begin
WHEN ZERO_DIVIDE THEN -- handles 'division by zero' error
INSERT INTO stats (symbol, ratio) VALUES ('XYZ', NULL);
COMMIT; ...
WHEN OTHERS THEN -- handles all other errors
ROLLBACK;
END; -- exception handlers and block end here
No more unhandled exceptions should result in no more ora 06512 errors and therefore your job will stop when when requested.
Here's some good info on exception handling in oracle
https://docs.oracle.com/cd/A97630_01/appdev.920/a96624/07_errs.htm
Hope that helps.
Related
I'm running into a behavior where I'm trying to use case-specific exception handlers for several Oracle PL/SQL blocks in a Flyway script and Oracle, apparently contradicting its documented scoping for exception handlers, sends all exceptions to the exception handler for the first block. For example, in this code:
begin
begin
execute immediate '
create table "test" (
"id" number not null,
"name" varchar2(100) not null,
constraint "test_pk" primary key ("id")
)
';
exception
when others then
if sqlcode != -955 then raise; end if;
end;
begin
execute immediate 'fail to create index "test_name_idx" on "test" ("name")';
exception
when others then
if sqlcode != -6512 then raise; end if;
end;
end;
the ORA-06512 exception is not caught, and the exception raised is tagged as from line 13.
Wrapping the blocks in more blocks doesn't help.
What is going on here? How do I stop this from happening?
This seems to be a bug, which has (so far) been reproduced in 11.2.0.4, 12.1.0.2 and 12.2.0.1. It doesn't seem to require DDL, or any real action in the first sub-block (though just doing null; as a placeholder doesn't trigger it, possibly because the compiler removes it), but it does seem to need the if inside both exception handlers:
begin
begin
dbms_output.put_line('Dummy message');
exception
when others then
dbms_output.put_line('In first exception handler');
if 1=1 then
raise;
end if;
end;
begin
execute immediate 'invalid';
exception
when others then
dbms_output.put_line('In second exception handler');
if 1=1 then
raise;
end if;
end;
end;
/
Dummy message
In second exception handler
ORA-00900: invalid SQL statement
ORA-06512: at line 8
ORA-06512: at line 13
As with your example the exception is thrown by line 13 so should be reported as (re-)raised at line 18; but it's instead it's reported as raised from line 8, which doesn't make sense. (The at line 13 message is only shown in 12.2; in 11.2 and 12.1 it only reports the first ORA-06512, which is rather more confusing. At least in 12 2 you have some clue where the problem really is.)
From the debugs you can see it doesn't actually use the first exception handler, and it does go into the second one. It 'only' seems to be reporting against the wrong line number, rather than executing the wrong code.
It appears that doing real work inside the if, immediately before the raise somehow fixes things - in either exception handling section; this adds a message in the first, which can't be reached:
begin
begin
dbms_output.put_line('Dummy message');
exception
when others then
dbms_output.put_line('In first exception handler');
if 1=1 then
dbms_output.put_line('This avoids the bug somehow');
raise;
end if;
end;
begin
execute immediate 'invalid';
exception
when others then
dbms_output.put_line('In second exception handler');
if 1=1 then
raise;
end if;
end;
end;
/
Dummy message
In second exception handler
ORA-00900: invalid SQL statement
ORA-06512: at line 19
ORA-06512: at line 14
and this in the second:
begin
begin
dbms_output.put_line('Dummy message');
exception
when others then
dbms_output.put_line('In first exception handler');
if 1=1 then
raise;
end if;
end;
begin
execute immediate 'invalid';
exception
when others then
dbms_output.put_line('In second exception handler');
if 1=1 then
dbms_output.put_line('This avoids the bug somehow');
raise;
end if;
end;
end;
/
Dummy message
In second exception handler
ORA-00900: invalid SQL statement
ORA-06512: at line 19
ORA-06512: at line 13
In both cases the reported line number is now correct. Somehow.
It doesn't have to be a dbms_output call, anything seems to work, such as a dummy procedure call or query, even an extra sub-block (e.g. begin execute immediate 'select * from dual'; end;, even though the query isn't executed because there's no into...). Again just using null; doesn't work though.
This is a bit ugly but gives you a way to stop it from happening at least, sort of.
It's clearly weird and unexpected and inconsistent behaviour, and has been around for a while, so it should probably be raised as a service request through My Oracle Support. I can't see any existing reports but I didn't look very hard so there might be one lurking somewhere.
I am learning how to write user-defined exceptions inside trigger using Oracle 11g XE and seems the answer for this question serves as a good example:
create or replace trigger trig1
before update
of sal
on emp
for each row
when (new.sal < old.sal)
declare
user_xcep EXCEPTION;
PRAGMA EXCEPTION_INIT( user_xcep, -20001 );
begin
raise user_xcep;
end;
/
However, when I try this an update a record with a value of sal lower than the original value, I get the following error:
Error starting at line : 24 in command -
update emp set sal = 1100 where id = 1001
Error report -
ORA-20001:
ORA-06512: at "USER01.TRIG1", line 5
ORA-04088: error during execution of trigger 'USER01.TRIG1'
I found from the Internet that this means a runtime error in the trigger code. But where is the problem? As the above code is from an answer written in 2013, because I am using a new version of Oracle, making the original trigger not working anymore? How should I fix it?
This happened because you need to specify what happened? when the custom error occurs:
Create Or Replace Trigger trig1
Before Update Of sal On emp
For Each Row
When (Nvl(new.sal, 0) < Nvl(old.sal, 0))
Declare
user_xcep Exception;
Pragma Exception_Init(user_xcep, -20001);
Begin
dbms_output.put_line('test');
Raise user_xcep;
Exception
When user_xcep Then
dbms_output.put_line('-'||sqlcode||' - '||sqlerrm);
When Others Then
dbms_output.put_line(sqlerrm);
End;
This you can defined using the Exception clause, first the custom errors and then the system errors like NO_DATA_FOUND, TO_MANY_ROWS and finally the OTHERS errors that catch any other error that occurr inside the trigger.
If you need to stop the program you can use the Raise_Application_Error inside the custom exception:
Raise_Application_Error(sqlcode, 'Custom Error Message');
Suppose I have 3 procedures running together, which insert record A,B,C respectively:
exec P1
exec P2
exec P3
Assume P2 will throw exception, while P1 and P3 are okay.
My expected flow is :
Run P1 -> A inserted -> Run P2 -> Encounter exception -> Rollback -> Stop from running P3
The ultimate expected outcome is nothing changed.
I have defined exception and exception handling for P2, which will rollback. However, I cannot stop it from running P3, i.e. C is still inserted.
Google tells me there is WHENEVER SQLERROR EXIT ROLLBACK, but I discovered that it could not work on self-defined exception. In other words, it only works on Oracle official exception, such as:
ERROR at line 2:
ORA-06550: line 2, column 10:
PLS-00201: identifier 'COLUMN_DOES_NOT_EXIST' must be declared
ORA-06550: line 2, column 3:
PL/SQL: SQL Statement ignored
To achieve the expected outcome, my thoughts are(but I don't know how to do it!):
Add exception handling to P2, such that it can stop P3 from running.
Run WHENEVER SQLERROR EXIT ROLLBACK before running the procedures. (but it can only work on Oracle official exception instead of my defined exception)
I do appreciate your help if you can fix either one.
The following is my code for your reference:
PROCEDURE INSERT(
INPUT IN TABLE.INPUT%TYPE DEFAULT NULL
) AS
BEGIN
IF INPUT NOT IN ('A','B','C') THEN
RAISE invalid_input;
END IF;
INSERT INTO (...) VALUES (...);
EXCEPTION
WHEN invalid_input THEN
DBMS_OUTPUT.PUT_LINE ('Invalid input' );
rollback; ---How to stop next procedure from running?
WHEN others THEN
rollback;
END;
When I run
exec INSERT(A)
exec INSERT(Y)
exec INSERT(C),
the outcome is that C is inserted, while I want nothing changed.
I added one line to your procedure (and changed a bit to run test example):
create or replace PROCEDURE ins(P_INPUT IN t.INPUT%TYPE DEFAULT NULL) AS
invalid_input exception;
BEGIN
IF P_INPUT NOT IN ('A','B','C') THEN
RAISE invalid_input;
END IF;
INSERT INTO t (INPUT) VALUES (P_INPUT);
EXCEPTION
WHEN invalid_input THEN
DBMS_OUTPUT.PUT_LINE ('Invalid input' );
rollback; ---How to stop next procedure from running?
raise; -- re-raise exception added
WHEN others THEN
rollback;
END;
Table:
create table t (input varchar2(1));
Test script:
SQL> declare
total_rows number;
begin
ins('A');
ins('D');
ins('C');
exception
when others then
select count(*) into total_rows from t;
dbms_output.put_line('Error ocured. Total rows in table T: ' || total_rows);
end;
/
Invalid input
Error ocured. Total rows in table T: 0
PL/SQL procedure successfully completed.
As I understand, it is your desired result.
IF l_value = 'FALSE' THEN
RAISE_APPLICATION_ERROR(-20299, 'some error message');
END IF;
This is part of table trigger. It should return me a error number and message, but when alert pops out it returns only message number. No 'some error message'. Whats wrong
Maybe the name RAISE_APPLICATION_ERROR is misleading for you. It will not pop up something onto your GUI. That you program yourself depending on what client you are using. Put you can use RAISE_APPLICATION_ERROR to create your own SQL errors on which you act upon.
Example
-- a example table
create table mytest (col_a number, col_b char(20));
-- a example trigger
CREATE OR REPLACE TRIGGER mytest_before
BEFORE UPDATE
ON mytest
FOR EACH ROW
DECLARE
BEGIN
if :new.col_a < 0 then
RAISE_APPLICATION_ERROR(-20299, 'negative value not allowed for column A');
end if;
END;
insert into mytest values (1,'hallo');
set serveroutput on
DECLARE
negative_value EXCEPTION; -- declare exception
PRAGMA EXCEPTION_INIT (negative_value, -20299); -- assign error code to exception
BEGIN
update mytest set col_a = -1 where col_b = 'hallo';
EXCEPTION
WHEN negative_value THEN -- handle exception
-- do whatever you need to do to bring the error to the user
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQLERRM(-20299)));
END;
/
The above will bring you the output in SQL*Plus or SQL Developer of that sort.
table MYTEST created.
TRIGGER mytest_before compiled
1 rows inserted.
anonymous block completed
ORA-20299: negative value not allowed for column A
ORA-06512: at "DEMO.MYTEST_BEFORE", line 4
ORA-04088: error during execution of trigger 'DEMO.MYTEST_BEFORE
Instead of DBMS_OUTPUT.PUT_LINE you can do whatever you need to do to show the user whatever you want him to show.
The alert in your form has been raised by some trigger code on your form. Have a look at your ON-ERROR trigger - what code does it have?
You may need to augment it to show DBMS_ERROR_TEXT in the alert.
create or replace procedure proc_advertisement(CustomerID in Number,
NewspaperID in number,
StaffID in Number,
OrderDate in date,
PublishDate in date,
Type in varchar,
Status in varchar,
Units in number) is
begin
insert into PMS.Advertisement(CustomerID, NewspaperID, StaffID, OrderDate, PublishDate,
Type, Status, Units)
values(CustomerID,NewspaperID, StaffID, OrderDate, PublishDate,
Type, Status, Units);
dbms_output.put_line('Advertisement Order Placed Successfully');
end;
How to check for if any error has occurred during the execution of the procedure and if any error has occurred then I wish to display an error message.
First of all, Oracle itself will raise an error message if any error occurs while running the procedure - for example:
ORA-02291: integrity constraint (EMP.MGR_FK) violated - parent key not Found
You can handle errors explicitly by writing an exception handler, but unless you do this well you are quite likely to just obfuscate the problem. For example you could simply add this (just before the END of your procedure:
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,'An error occured');
But now your user won't know what kind of error, whereas before they could infer that it was that the specified Manager did not exist. You could show the original error also like this:
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,'An error occured: '||SQLERRM);
if that adds any value. Or you could just show a generic error and then write the value of SQLERRM to a log table.
You can also handle particular exceptions: for example
PROCEDURE ... IS
e_invalid_fk EXCEPTION;
PRAGMA EXCEPTION_INIT(e_invalid_fk,-2291);
BEGIN
...
EXCEPTION
WHEN e_invalid_fk THEN
IF SQLERRM LIKE '%(EMP.MGR_FK)%' THEN
raise_application_error(-20001,'Invalid manager specified');
ELSE
RAISE;
END IF;
END;
Note the RAISE: if any part of your exception handler doesn't issue either a RAISE or a RAISE_APPLICATION_ERROR then you are effectively sweeping the exception under the carpet - the user will think the procedure worked.
By the way, DBMS_OUTPUT.PUT_LINE is great for trying things out and debugging, in SQL Plus or an IDE, but it has no place in real code as users and applications that call the procedure will never see the output it produces.