Oracle not able to insert exception into table - sql

I have below procedure where i am trying to track the exceptions into I_Log table.To test whether its working or not I have made a ORA-00933: SQL command not properly ended error in my query where I am trying to insert into I_OPTION table. When i run this procedure the dbms output line is printing the error below but its not getting inserted into I_Log table:
OTHERS exception in EXT_I_OPTION - ID:1000196-933----ORA-00933: SQL command not properly ended
Below is my procedure:
CREATE OR REPLACE PROCEDURE
"EXT_I_OPTION"(in_id IN NUMBER DEFAULT 0)
AS
err_code VARCHAR(100);
err_msg VARCHAR(100);
in_event_id NUMBER;
in_db_link VARCHAR2(50);
in_env_id NUMBER;
l_sql VARCHAR2(5000);
l_sql1 VARCHAR2(5000);
BEGIN
FOR I_row IN I_cur
LOOP
l_sql2 := INSERT INTO I_OPTION(ID)
select DISTINCT(SO.ID)
)
from Icard I;
END LOOP;
EXCEPTION WHEN OTHERS THEN
err_code := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 200);
INSERT INTO I_log (I_ID)
VALUES (i_id);
RAISE;
COMMIT;
END ext_I_option;

It seems that you have a RAISE before COMMIT; this way, the error will be raised before doing COMMIT, so you don't find data in your log table.
According to suggestions, you should define a procedure to handle your log table:
CREATE OR REPLACE procedure i_LOG (...) AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
Insert into I_LOG(...);
COMMIT;
END;
/
This procedure runs in a separate transaction, so it only does commit of log data, with no conflict with data you modify in your main procedure.
Then you should modify your error handling in this way, avoiding COMMIT statement, that can be really dangerous, saving partial, unconsistent data:
DBMS_OUTPUT.PUT_LINE('OTHERS exception in EXT_I_OPTION - ID:'||to_char(ID) || err_code || '----' || err_msg );
ins_I_LOG(...);
RAISE;

Related

Exception handling for insert statements in plsql code

if i have 3 insert statements in my plsql code.
lets assume them as insert_1, insert_2, insert_3.
my conditions be like : if insert_1 statement successfully executed then automatically insert_3 should be executed as well as if insert_3 executed successfully then insert_1 also should be executed automatically.
if both insert_1 and insert_3 fails then only insert_2 should be executed.
please write plsql code for this requirement.
You can create a package for this:
create a package and inside package body you try something like this.
create or replace PACKAGE BODY PKG_INSERT_QUERY AS
P_ERR_CODE number;
procedure finalPro
is
begin
P_ERR_CODE := 0;
insert into a values('a');
commit;
EXCEPTION WHEN OTHERS THEN ROLLBACK;
DBMS_OUTPUT.PUT_LINE('ERROR ' ||SQLERRM);
P_ERR_CODE := 1;
if(P_ERR_CODE < 1 )then
secondQ;
IF(P_ERR_CODE < 1) THEN
thirdQ;
END IF;
END IF;
end;
procedure secondQ
as
begin
insert into B values('B');
commit;
EXCEPTION WHEN OTHERS THEN ROLLBACK;
DBMS_OUTPUT.PUT_LINE('ERROR ' ||SQLERRM);
P_ERR_CODE := 2;
end;
procedure thirdQ
as
begin
insert into C values('C');
commit;
EXCEPTION WHEN OTHERS THEN ROLLBACK;
DBMS_OUTPUT.PUT_LINE('ERROR ' ||SQLERRM);
P_ERR_CODE := 3;
end;
end;

Assign function to a variable and use it within procedure

I am getting a problem with using 'Next Sequence Values' inside a procedure.
I have my 'external' function to return the Next Value of Sequence.
Inside my procedure, i want to assign the values of that sequence into a variable
and use that variable inside my cursor (since i am using a union statement in my cursor).
But it is not working.
CREATE OR REPLACE Procedure HR.insert_TBL_APP is
--declare variables for insert
v_TA_SNO VARCHAR2(10);
v_TA_SEQNO VARCHAR2(6);
v_TA_DESC VARCHAR2(10);
--declare variable to store the sequence number
var_TaSeqno varchar2(6);
-- Validation
v_check VARCHAR2 (10 Byte);
err_code varchar2(50);
err_msg varchar2(100);
v_table_name varchar2(50):='TBL_APP';
error_found exception;
cursor c1 is
select distinct TA_SNO,
TA_SEQNO,
TA_DESC
from (
SELECT hdr.FIRST_NO TA_SNO,
var_TaSeqno TA_SEQNO, -- using variable to assign the sequence no
hdr.descrip TA_DESC
FROM
FORMS_HDR hdr
WHERE
hdr.seco_name = 'TST121'
union
SELECT hdr.FIRST_NO TA_SNO,
var_TaSeqno TA_SEQNO, -- using variable to assign the sequence no
hdr.descrip TA_DESC
FROM
FORMS_HDR hdr
WHERE
hdr.seco_name = 'TST122');
begin
if c1%isopen then
close c1;
end if;
v_check:=null;
FOR i IN c1 LOOP
--assign variables for insert
v_TA_SNO := i.TA_SNO;
v_TA_SEQNO := i.TA_SEQNO;
v_TA_DESC := i.TA_DESC;
begin
-- calling the Function taSeqNoFunc and assign the
--sequence No into the variable var_TaSeqno
var_TaSeqno := HR.taSeqNoFunc();
select TA_SNO
into v_check
from TBL_APP a
where TA_SNO = i.TA_SNO
and TA_SEQNO =i.TA_SEQNO;
exception
when no_data_found then
--insert into target table
INSERT INTO TBL_APP (TA_SNO,
TA_SEQNO,
TA_DESC
)
values (v_TA_SNO,
v_TA_SEQNO,
v_TA_DESC
);
when others then
raise error_found;
end ;
end loop;
exception when error_found then
rollback;
err_code := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 200);
insert into TA_ERROR_LOG values (v_check,v_table_name,'An error
was encountered '||err_code||':'||err_msg,sysdate);
commit;
raise_application_error(err_code,err_msg);
end;
/
The error finally goes into raise_application_error near the end:
"ORA-21000: error number argument to raise_application_error of 1 is out of range"
Please help me. Thank you.
The raise_application_error() procedure is an Oracle PL/SQL built-in. It's provided so what we can associate a custom message to a user-defined exception. User-defined exceptions must have numbers in the range -20999 to -20000. Find out more.
You are getting this error because of this code in your inner EXCEPTION block:
when others then
raise error_found;
You are raising a user-defined exception but one you haven't associated to an error number with the EXCEPTION_INIT pragma. Find out more. So, Oracle defaults to SQLCODE = 1, SQLERRM = 'User-Defined Exception'.
Clearly 1 is outside the permitted range of raise_application_error(). Hence the error when you come to the outer EXCEPTION block.
The way to avoid this is to remove the ERROR_FOUND exception and rely on Oracle's default exception handling.
In the innermost block you want to re-raise any exception except NO_DATA_FOUND. The simplest way to do that is remove the WHEN OTHERS clause. Then, in the outer block you will have meaningful values for SQLCODE and SQLERRM which you can log. Then just use RAISE to propagate them up the stack....
exception
when others then
rollback;
err_code := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 200);
insert into TA_ERROR_LOG values (v_check,v_table_name,'An error
was encountered '||err_code||':'||err_msg,sysdate);
commit;
raise;
end;
Not only will you not get an error from raise_application_error(), your log will contain a useful error number and message.
Incidentally, it is bad practice to use ROLLBACK and COMMIT like that in an EXCEPTION block. A better approach is to write a logging procedure which is covered by the AUTONOMOUS_TRANSACTION pragma. That way the logging won't interfere with the wider transaction. Find out more.
The error number you pass to the raise_application_error procedure must be a negative integer in the range -20000..-20999.
For user-defined exceptions SQLCODE returns always +1, so you're passing +1 as
the error number to the raise_application_error procedure and that's out of range.
I have posted the answer. It can be further improved.
The pragma exception_init is used to catch the error (in my case - Integrity Constraint).
I have removed the function to call 'next sequence value' since it can be called directly just before performing the insert.
#APC Thanks :)
CREATE OR REPLACE Procedure HR.insert_TBL_APP is
--declare variables for insert
v_TA_SNO VARCHAR2(10);
v_TA_SEQNO VARCHAR2(6);
v_TA_DESC VARCHAR2(10);
-- Validation
v_check VARCHAR2 (10 Byte);
err_code varchar2(50);
err_msg varchar2(200);
v_table_name varchar2(50):='TBL_APP';
error_found exception;
parent_not_found exception; -- use it to catch the Integrity Constraint
pragma exception_init(parent_not_found, -2291);
cursor c1 is
select distinct TA_SNO,
TA_SEQNO,
TA_DESC
from (
SELECT hdr.FIRST_NO TA_SNO,
-1 TA_SEQNO, -- assign a dummy value as sequence no
hdr.descrip TA_DESC
FROM
FORMS_HDR hdr
WHERE
hdr.seco_name = 'TST121'
union
SELECT hdr.FIRST_NO TA_SNO,
-2 TA_SEQNO, -- assign a dummy value as sequence no
hdr.descrip TA_DESC
FROM
FORMS_HDR hdr
WHERE
hdr.seco_name = 'TST122');
begin
if c1%isopen then
close c1;
end if;
v_check:=null;
FOR i IN c1 LOOP
--assign variables for insert
v_TA_SNO := i.TA_SNO;
v_TA_SEQNO := i.TA_SEQNO;
v_TA_DESC := i.TA_DESC;
begin
--var_TaSeqno := HR.taSeqNoFunc(); --the variable will not be used
select TA_SNO
into v_check
from TBL_APP a
where TA_SNO = i.TA_SNO
and TA_SEQNO =i.TA_SEQNO;
exception
when no_data_found then
Begin -- added line to use exception
--insert into target table
INSERT INTO TBL_APP (TA_SNO,
TA_SEQNO,
TA_DESC
)
values (v_TA_SNO,
TA_SEQNO.nextval, --insert the nextval directly
v_TA_DESC
);
--when the integrity constraint (parent key) error is thrown, insert into the TA_ERROR_LOG
exception
when parent_not_found then
rollback;
err_msg := SUBSTR(SQLERRM, 1, 200);
insert into TA_ERROR_LOG values (v_check,v_table_name, err_msg, sysdate);
commit;
end; -- end begin for using the exception
when others then
raise error_found;
end ;
end loop;
exception when error_found then
rollback;
err_code := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 200);
insert into TA_ERROR_LOG values (v_check,v_table_name, err_msg, sysdate);
commit;
raise_application_error(err_code,err_msg);
end;

Trigger error "ORA-01403: no data found" when It is not fire

I am creating a trigger below, as long as I insert something already existed in the table, then print other wise do nothing.
create or replace trigger TR_insert
Before INSERT On A
For each row
DECLARE
l_act integer;
l_name varchar(30);
l_minute integer;
Begin
select count(1) into l_act
From A
Where Activity=:new.Activity;
if(l_act>0) then
DBMS_OUTPUT.PUT_LINE ('There is duplicate.');
else
DBMS_OUTPUT.PUT_LINE('');
end if;
end;
It is working fine when I insert something existed, but when I insert new item, then it gives out error "SQL Error: ORA-01403: no data found", why is that please?
You're getting the error because your select does not return any value for your new item. The below shud work.
begin
select count(1) into l_act
From A
Where Activity=:new.Activity;
if(l_act>0) then
DBMS_OUTPUT.PUT_LINE ('There is duplicate.');
end if;
exception
when NO_DATA_FOUND then
DBMS_OUTPUT.PUT_LINE('');
end;

Oracle procedure stops running

I have an Oracle stored procedure that is called from a .NET application. It runs for over 15 minutes. It is very simple code that inserts into a big table from a smaller table, then clears the smaller table.
My issue is that it runs for like 15 minutes, then it dies. No error messages in the log. Nothing. Just stops running. I have done a SQL trace, no evidence of an issue. Sometimes it works, sometimes it doesn't.
Some consistencies exist - when it does fail, it never gets to the Data Moved Successfully or Exception section. Just appears to stop running.
PROCEDURE C_X_AllocInsertData(
p_AccountTable VARCHAR2,
p_AllocationTable VARCHAR2,
p_YearMonth NUMBER,
p_versionPK NUMBER,
p_returncode OUT NUMBER)
AS PRAGMA AUTONOMOUS_TRANSACTION;
v_OutputTableRowCntSql varchar(32767);
BEGIN
p_returncode:=0;
C_X_VERSIONINSERTLOG(
p_VersionPk
,'Now moving the data from temp table to big table'
,'Now moving the data from temp table to big table'
);
--Now that all operations are complete, delete from account table
v_OutputTableRowCntSql := 'BEGIN delete from '||p_AccountTable||' where YEARMONTH= '||p_YearMonth||'; ';
--Then insert from the TMP table
v_OutputTableRowCntSql := v_OutputTableRowCntSql || 'insert into '||p_AccountTable|| ' SELECT * FROM ' || p_AllocationTable||'; ';
--Then clear the temp table
v_OutputTableRowCntSql := v_OutputTableRowCntSql || 'delete from '||p_AllocationTable||'; END;';
EXECUTE IMMEDIATE v_OutputTableRowCntSql;
C_X_VERSIONINSERTLOG(
p_VersionPk
,'Data moved successfully.'
,'Data moved successfully.'
);
commit;
EXCEPTION
WHEN OTHERS THEN
p_returncode:=-1;
C_X_VERSIONINSERTLOG(
p_VersionPk
,'Insert into big table failed for version #'||p_versionPK||'... Error message was: '||SQLERRM
,'Insert into big table failed. Error message was: '||SQLERRM||' Statement was: '||v_OutputTableRowCntSql
);
END;
It seems that C_X_VERSIONINSERTLOG procedure lacks appropriate error handing...I will add that. Here it is in its original form...could this be the issue?
PROCEDURE C_X_VERSIONINSERTLOG
(
P_VERSIONPK NUMBER,
P_LOGTEXT VARCHAR2,
P_ERROR_MSG VARCHAR2)
AS PRAGMA AUTONOMOUS_TRANSACTION;
v_VersionLogPk C_X_VERSIONLOG.VersionLogPk%TYPE;
BEGIN
SELECT C_X_VERSIONLOG_SEQ.nextval INTO v_VersionLogPk FROM DUAL;
INSERT
INTO C_X_VERSIONLOG
(
VersionLogPk,
VERSIONPK,
VERSIONLOGTEXT,
VERSIONLOGTECHNICALTEXT,
VERSIONLOGDATE
)
VALUES
(
v_VersionLogPk,
P_VERSIONPK,
P_LOGTEXT,
P_ERROR_MSG ,
CURRENT_TIMESTAMP
);
COMMIT;
END C_X_VERSIONINSERTLOG;

Trigger calling procedure error

I am having some troubles with this trigger. I created a procedure to check and see if salary is within a certain boundary. If it fails to fall within a certain range, raise the exception. The problem is even though the procedure compiles with no errors, the trigger can not find the procedure.
set serveroutput on;
create or replace procedure check_salary (
tmp_id in varchar2,
tmp_sal in number
)
IS
v_sal number(6,0) := tmp_sal;
v_min number(6,0);
v_max number(6,0);
ex_fail exception;
cursor cur_select is
select min_salary, job_id, max_salary
from jobs where job_id = tmp_id;
BEGIN
for rec_something in cur_select loop
v_min := rec_something.min_salary;
v_max := rec_something.max_salary;
if v_sal >= v_min and v_sal <= v_max then
raise ex_fail;
end if;
end loop;
exception
when ex_fail then
dbms_output.put_line('Invalid salary ' || v_sal || ' must be between ' || v_min || ' and ' || v_max ||'.');
END;
/
show errors;
create or replace trigger check_salary_trg
after insert or update on employees
for each row
declare
begin
IF UPDATING or INSERTING THEN
execute check_salary(:NEW.job_id, :NEW.salary);
end if;
end;
/
show errors;
The Error Message:
PROCEDURE check_salary compiled
No Errors.
TRIGGER check_salary_trg compiled
Warning: execution completed with warning
5/13 PLS-00103: Encountered the symbol "CHECK_SALARY" when expecting one of the following:
:= . ( # % ; immediate
The symbol ":=" was substituted for "CHECK_SALARY" to continue.
Change it to:
create or replace trigger check_salary_trg
after insert or update on employees
for each row
begin
IF UPDATING or INSERTING THEN
check_salary(:NEW.job_id, :NEW.salary);
end if;
end;
/
When you are executing a procedure within a PL/SQL block, you do not use the
EXECUTE syntax
More information about execute you can check the below link
http://docstore.mik.ua/orelly/oracle/prog2/ch23_01.htm
The stack overflow exception is due to the use of dbms_output.put_line inside check_salary procedure.
SQL*Plus command set serveroutput on reserves little size as default, you must specify the buffer size or remove the dbms_output.put_line from check_salary procedure.
In order to increase default buffer size use this:
set serveroutput on size 1000000