exceptions in other procedure without exiting the procedure - oracle

I have a materialized view of the REFRESH FAST ON DEMAND type, I have a stored procedure to refresh several materialized views. How can I make an exception that records in an error log table, but does not stop the procedure, that records the error line, but continue with the refresh of the following materialized view 2. The materialized views generate a lot of problems, like handling a table of loading errors?
Thank you.
create or replace procedure actualizar_vistaM
is
begin
DBMS_MVIEW.REFRESH('VIEW 1')
DBMS_MVIEW.REFRESH('VIEW 2')
exception
when others then
INSERT INTO errors VALUES (value1,value2,value3)
end;

I guess you'd have to enclose each refresh into its own begin-exception-end block.
create or replace procedure actualizar_vistaM
is
begin
begin
DBMS_MVIEW.REFRESH('VIEW 1');
exception
when others then
insert into errors values (...);
end;
--
begin
DBMS_MVIEW.REFRESH('VIEW 2');
exception
when others then
insert into errors values (...);
end;
end;

Related

how to insert the result of dbms_output.put_line to a table for error catch?

Exception
WHEN OTHERS THEN
--dbms_output.put_line('pl_update_sidm_user r: ERROR CODE:' || sqlcode || '~' ||
--sqlerrm || ' EMPL_NBR:' || r.EMPL_NBR);
insert into ERROR_MSG (ERROR_MSG_ID,ERROR_MSG) values (ERROR_MSG_ID_SEQ.NEXTVAL, 'pl_update_sidm_user_duty_role r2');
END;
I would like to put the error result to a table.
However, how can I do that?
Can I put the result of dbms_output to a table as a string?
If not, can I get the sqlcode,sqlerrm without using dbms_output?
Thank you !!
From the documentation,
A SQL statement cannot invoke SQLCODE or SQLERRM. To use their values
in a SQL statement, assign them to local variables first
Also,
Oracle recommends using DBMS_UTILITY.FORMAT_ERROR_STACK except when using the FORALL statement with its SAVE EXCEPTIONS clause
So, for SQLCODE or SQLERRM, you should assign them into variables and use them.
DECLARE
v_errcode NUMBER;
v_errmsg VARCHAR2(1000);
BEGIN
--some other statements that may raise exception.
EXCEPTION
WHEN OTHERS THEN
v_errcode := SQLCODE;
v_errmsg := SQLERRM;
insert into ERROR_TABLE (ERROR_MSG_ID,ERROR_MSG) --change your table name
values (ERROR_MSG_ID_SEQ.NEXTVAL,
v_errcode||':'||v_errmsg);
END;
/
Preferably use insert like this instead, as per Oracle's recommendation.
insert into ERROR_TABLE (ERROR_MSG_ID,ERROR_MSG) values (ERROR_MSG_ID_SEQ.NEXTVAL,
DBMS_UTILITY.FORMAT_ERROR_STACK);
Demo
Technically what others are suggesting is correct: the "insert" operation executed in the "exception when others" block will actually insert a new row in the log table.
the problem is that such insert statement will be part of the same transaction of the main procedure and, since you had an error while executing it, you are very likely to rollback that transaction, and this will rollback also the insert in your log table
I suppose the problem you are facing is not that you aren't successfully logging the error message: it is that you are rolling it back immediately afterwards, along with all the other writes you did in the same transaction.
Oracle gives you a way of executing code in a SEPARATE transaction, by using "autonomous transaction" procedures.
you need to create such a procedure:
create or replace procedure Write_Error_log(
arg_error_code number,
arg_error_msg varchar2,
arg_error_backtrace varchar2) is
PRAGMA AUTONOMOUS_TRANSACTION;
begin
INSERT INTO error_msg (
error_msg_id,
error_code,
error_msg,
error_stack)
VALUES (
error_msg_id_seq.NEXTVAL,
arg_error_code,
arg_error_msg,
arg_error_backtrace);
commit; -- you have to commit or rollback always, before exiting a
-- pragma autonomous_transaction procedure
end;
What this procedure does is to write a new record in the log table using a totally separate and independent transaction: the data will stay in the log table even if you execute a roll back in your calling procedure. You can also use such a procedure to create a generic log (not only errors).
All you have to do now is to call the procedure above whenever you need to log something, so your code becomes:
DECLARE
v_errcode NUMBER;
v_errmsg VARCHAR2(1000);
BEGIN
--some other statements that may raise exception.
EXCEPTION WHEN OTHERS THEN
Write_Error_log(SQLCODE, SQLERRM, dbms_utility.format_error_backtrace);
END;
/
P.S: there might be some typos in my code: I can't test it right now since I can't reach an oracle server in this moment.

Can I use if statements in a stored procedure to insert values into a table?

I am trying to write a stored procedure that selects indiv_ids and transaction_ids and inserts these into a table on my schema. In doing so, I want to pass in variables and have the stored procedure use if statements to select the indiv_ids and transaction_ids from different tables depending on the information passed in. I've tried a few variations and can't get the procedure to work without an error. Thanks!
create or replace procedure myproc (name_type in varchar2, dept in number)
is begin
if name_type='promo' then insert into mytable(indiv_id,transaction_id)
---sql here;
commit;
elsif name_type='deal' then insert into mytable(indiv_id, transaction_id)
---sql here;
commit;
end if;
end;
errors: Error(8,10): PL/SQL: SQL Statement ignored,
Error(16,31): PL/SQL: ORA-00942: table or view does not exist
Note that name_type variable is declared as NUMBER, but in the procedure body it is compared with strings:
if name_type='promo' then
This is not the cause of ORA-00942 error, but anyway it makes your procedure not working correctly.

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

Why does this Oracle PLSQL function need to be recompiled when a table is updated?

I have written this function for an Oracle db for a class project:
create or replace Function loginUser ( name_in IN varchar2, pass_in IN varchar2 )
Return Number
IS
cursor c1 is
SELECT u_id
FROM userinfo
WHERE username = name_in AND pass = pass_in AND lockedout='N';
user_id_return number;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
open c1;
fetch c1 into user_id_return;
if c1%notfound then
user_id_return := 0;
INSERT INTO LoginAttempt(username, whenattempted, attempt_status) VALUES (name_in, SYSDATE, 'N');
commit;
ELSE
INSERT INTO LoginAttempt(username, whenattempted, attempt_status) VALUES (name_in, SYSDATE, 'Y');
commit;
END IF;
close c1;
Return user_id_return;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END;
It works great, I get an insert into a table called LoginAttempt when you call
SELECT loginUser('name','pass') FROM DUAL;
The issue, however, is that new records and updates to userinfo are not reflected in the SELECT statement at the top of the function.
I have to recompile the function each time I update the userinfo table.
Why is this? Is this how functions with SELECT statements work? Is the table that is being SELECTED from compiled when the function is compiled?
Is this related to the PRAGME AUTONOMOUS_TRANSACTION bit?
The schema for the table can be found on github (https://github.com/tmsimont/cs3810schema/blob/master/export.sql)
Because your function executes its DML in an autonomous transaction (i.e. a separate session to the calling one), it cannot see data that has not been committed by the calling session. Until your code commits, the changes it makes are not visible to any other session, including the one used by your function.
This has nothing to do with needing to compile the function. The reason compilation caused it to suddenly see the data is because DDL always issues a commit, thus having the side effect of committing the data you had inserted.

RAISE_APPLICATION_ERROR doesn't return the message

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.

Resources