Oracle procedure stops running - sql

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;

Related

Oracle not able to insert exception into table

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;

drop table If it exists in Oracle (IF EXIST) [duplicate]

This question already has answers here:
Oracle: If Table Exists
(16 answers)
Closed 6 years ago.
I am using Oracle 12c and I am not interesting to have an error while droping my table 'CONTINENT' in case it doesn't exist.
I did this
set echo on
set serveroutput on
alter session set current_schema=WORK_ODI;
set verify off
set pause off
begin
execute immediate 'drop table continent';
exception when others then null;
end;
This script is work with me well. and I use this script too :
declare
c int;
begin
select count(*) into c from user_tables where table_name = upper('continent');
if c = 1 then
execute immediate 'drop table continent';
end if;
end;
the both scripts work well but my boss wants something like IF EXIT. Anybody can help me please. how to use IF EXIT in this case ?
Sorry, there is no if exists in the Oracle's drop table syntax.
You can do two things
define the exception you want to ignore (here ORA-00942)
add an undocumented (and not implemented) hint /*+ IF EXISTS */ that will pleased you management.
.
declare
table_does_not_exist exception;
PRAGMA EXCEPTION_INIT(table_does_not_exist, -942);
begin
execute immediate 'drop table continent /*+ IF EXISTS */';
exception when table_does_not_exist then
DBMS_OUTPUT.PUT_LINE('Ignoring table or view does not exist')
;
end;
/
Additional note: the usage of
exception when others then null;
may be dangerous, as for example you ignore also errors such as tablespace offline, when the table is NOT DROPPED.
set echo on
set serveroutput on
alter session set current_schema=WORK_ODI;
set verify off
set pause off
WHENEVER OSERROR EXIT FAILURE ROLLBACK
drop table continent;
WHENEVER OSERROR CONTINUE
I had a similar problem - i needed a way how to repeat DDL scripts without modifying them. Imaging the following script:
create table tab1(...);
create table tab2(...);
create table tab3{...}; /* <--- this one fails*/
create table tab4(...);
so now we have the following situation: tables "tab1" and "tab2" have been successfully created, "tab3" and "tab4" are missing.
So after fixing statement for the "tab3" table we would have to comment out create statements for "tab1" and "tab2" - it might be very annoying when working with big SQL scripts containing many DDLs and many bugs.
So i came up with the following procedure which allows to re-run DDL statements:
create or replace procedure re_run_ddl (p_sql in varchar2)
AUTHID CURRENT_USER
as
l_line varchar2(500) default rpad('-',20,'-');
l_cr varchar2(2) default chr(10);
l_footer varchar2(500) default l_cr||rpad('*',20,'*');
l_ignore_txt varchar2(200) default 'IGNORING --> ';
ORA_00955 EXCEPTION;
ORA_01430 EXCEPTION;
ORA_02260 EXCEPTION;
ORA_01408 EXCEPTION;
ORA_00942 EXCEPTION;
ORA_02275 EXCEPTION;
ORA_01418 EXCEPTION;
ORA_02443 EXCEPTION;
ORA_01442 EXCEPTION;
ORA_01434 EXCEPTION;
ORA_01543 EXCEPTION;
ORA_00904 EXCEPTION;
ORA_02261 EXCEPTION;
ORA_04043 EXCEPTION;
ORA_02289 EXCEPTION;
PRAGMA EXCEPTION_INIT(ORA_00955, -00955); --ORA-00955: name is already used by an existing object
PRAGMA EXCEPTION_INIT(ORA_01430, -01430); --ORA-01430: column being added already exists in table
PRAGMA EXCEPTION_INIT(ORA_02260, -02260); --ORA-02260: table can have only one primary key
PRAGMA EXCEPTION_INIT(ORA_01408, -01408); --ORA-01408: such column list already indexed
PRAGMA EXCEPTION_INIT(ORA_00942, -00942); --ORA-00942: table or view does not exist
PRAGMA EXCEPTION_INIT(ORA_02275, -02275); --ORA-02275: such a referential constraint already exists in the table
PRAGMA EXCEPTION_INIT(ORA_01418, -01418); --ORA-01418: specified index does not exist
PRAGMA EXCEPTION_INIT(ORA_02443, -02443); --ORA-02443: Cannot drop constraint - nonexistent constraint
PRAGMA EXCEPTION_INIT(ORA_01442, -01442); --ORA-01442: column to be modified to NOT NULL is already NOT NULL
PRAGMA EXCEPTION_INIT(ORA_01434, -01434); --ORA-01434: private synonym to be dropped does not exist
PRAGMA EXCEPTION_INIT(ORA_01543, -01543); --ORA-01543: tablespace '<TBS_NAME>' already exists
PRAGMA EXCEPTION_INIT(ORA_00904, -00904); --ORA-00904: "%s: invalid identifier"
PRAGMA EXCEPTION_INIT(ORA_02261, -02261); --ORA-02261: "such unique or primary key already exists in the table"
PRAGMA EXCEPTION_INIT(ORA_04043, -04043); --ORA-04043: object %s does not exist
PRAGMA EXCEPTION_INIT(ORA_02289, -02289); --ORA-02289: sequence does not exist
procedure p(
p_str in varchar2
,p_maxlength in int default 120
)
is
i int := 1;
begin
dbms_output.enable( NULL );
while ( (length(substr(p_str,i,p_maxlength))) = p_maxlength ) loop
dbms_output.put_line(substr(p_str,i,p_maxlength));
i := i + p_maxlength;
end loop;
dbms_output.put_line(substr(p_str,i,p_maxlength));
end p;
begin
p( 'EXEC:'||l_cr||l_line||l_cr||p_sql||l_cr||l_line );
execute immediate p_sql;
p( 'done.' );
exception
when ORA_00955 or ORA_01430 or ORA_02260 or ORA_01408 or ORA_00942
or ORA_02275 or ORA_01418 or ORA_02443 or ORA_01442 or ORA_01434
or ORA_01543 or ORA_00904 or ORA_02261 or ORA_04043 or ORA_02289
then p( l_ignore_txt || SQLERRM || l_footer );
when OTHERS then
p( SQLERRM );
p( DBMS_UTILITY.FORMAT_ERROR_BACKTRACE );
p( l_footer );
RAISE;
end;
/
show err
Usage example:
set serveroutput on
begin
re_run_ddl('
create table test
(
id number,
s varchar2(30)
)
');
end;
/
exec re_run_ddl('drop table test');
exec re_run_ddl('drop table test');
exec re_run_ddl('drop table test');
Output:
EXEC:
--------------------
create table test
(
id number,
s varchar2(30)
)
--------------------
done.
PL/SQL procedure successfully completed.
EXEC:
--------------------
drop table test
--------------------
done.
PL/SQL procedure successfully completed.
stx11de2> EXEC:
--------------------
drop table test
--------------------
IGNORING --> ORA-00942: table or view does not exist
********************
PL/SQL procedure successfully completed.
stx11de2> EXEC:
--------------------
drop table test
--------------------
IGNORING --> ORA-00942: table or view does not exist
********************
PL/SQL procedure successfully completed.

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

cannot perform DML operation inside a query

I cannot convince why I can't add DML operation inside Oracle Function especially inside cursor loop. I feel Oracle don't support DML operation inside cursor loop.
How can I do If I need to insert into table inside cursor loop? Create new store procedure inside it or something else?
Error Message : cannot perform DML operation inside a query
Here is my function,
CREATE OR REPLACE FUNCTION TEST_FUNC(U_ID IN VARCHAR2)
RETURN VARCHAR2
IS
V_MESSAGE VARCHAR2(30);
CURSOR C_PERSON (V_ID VARCHAR2) IS
SELECT NAME_UPPER
FROM TBL_PERSON
WHERE NAME_UPPER = V_ID;
BEGIN
FOR C_PERSON_CURSOR IN C_PERSON(U_ID)
LOOP
INSERT INTO TMP_PERSON(NAME) VALUES (C_PERSON_CURSOR.NAME_UPPER);
END LOOP;
RETURN V_MESSAGE;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END;
You can use DML inside a PL/SQL function - no problem. However, the function can only be called from PL/SQL, not from SQL - i.e. it can be called like this:
declare
l_message varchar2(30);
begin
l_message := test_func('123');
end;
... but not like this:
select test_func(empno) from emp;
That leads to the error message you posted.
Many people (including me) don't like functions that have "side effects" like this, but that is a matter of best practice and standards, not a technical issue.
You can perform DML operations inside an Oracle PL/SQL function and, although this is generally not a good practice, call it from SQL. The function has to be marked with a pragma AUTONOMOUS_TRANSACTION and the transaction has to be committed or rolled back before exiting the function (see AUTONOMOUS_TRANSACTION Pragma).
You should be aware that this kind of function called from SQL can dramatically degrade your queries performances. I recommend you use it only for audit purposes.
Here is an example script starting from your function:
CREATE TABLE TBL_PERSON (NAME_UPPER VARCHAR2(30));
CREATE TABLE TMP_PERSON (NAME VARCHAR2(30));
INSERT INTO TBL_PERSON (NAME_UPPER) VALUES ('KING');
CREATE OR REPLACE FUNCTION TEST_FUNC(U_ID IN VARCHAR2)
RETURN VARCHAR2
IS
PRAGMA AUTONOMOUS_TRANSACTION; -- Needed to be called from SQL
V_MESSAGE VARCHAR2(2000);
CURSOR C_PERSON (V_ID VARCHAR2) IS
SELECT NAME_UPPER
FROM TBL_PERSON
WHERE NAME_UPPER = V_ID;
BEGIN
FOR C_PERSON_CURSOR IN C_PERSON(U_ID)
LOOP
INSERT INTO TMP_PERSON(NAME) VALUES (C_PERSON_CURSOR.NAME_UPPER);
V_MESSAGE := SQL%ROWCOUNT
|| ' Person record successfully inserted into TMP_PERSON table';
END LOOP;
COMMIT; -- The current autonomous transaction need to be commited
-- before exiting the function.
RETURN V_MESSAGE;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END;
/
PROMPT Call the TEST_FUNC function and insert a new record into TMP_PERSON table
SELECT TEST_FUNC('KING') FROM DUAL;
PROMPT Content of the TMP_PERSON table
COL NAME FOR A30
SELECT * FROM TMP_PERSON;
When running the previous script we get the following output:
Table created.
Table created.
1 row created.
Function created.
Calling the TEST_FUNC function and insert a new record into TMP_PERSON table
TEST_FUNC('KING')
------------------------------------------------------------
1 Person record successfully inserted into TMP_PERSON table
Content of the TMP_PERSON table
NAME
------------------------------
KING

is there any way to log all failed sql statements in oracle 10g

is there any way to log all failed sql statements in oracle 10g to a table or file?
By failed I mean bad formated sql statement or sql statements that do not have permission for a table or object.
You may want to use Auditing like:
AUDIT SELECT TABLE, INSERT TABLE, DELETE TABLE, EXECUTE PROCEDURE
BY ACCESS
WHENEVER NOT SUCCESSFUL;
By ACCESS is for each statement (which seems like what you want). By SESSION would record one record per session (high volume environment).
Oracle's built in auditing has less overhead then a trigger. A trigger, which other answers contain, allows you to log the exact information you want. Auditing will also only catch hits on existing objects. If someone selects on a non-existent table (misspelled or whatnot) auditing will not catch it. The triggers above will.
A lot more info in the security guide: http://download.oracle.com/docs/cd/B19306_01/network.102/b14266/auditing.htm#i1011984
Rather than hit the system views, as in Demge's answer, there is an ora_sql_txt function that gives the relevant statement.
create or replace TRIGGER log_err after servererror on schema
DECLARE
v_stack VARCHAR2(2000) := substr(dbms_utility.format_error_stack,1,2000);
v_back VARCHAR2(2000);-- := substr(dbms_utility.format_error_backtrace,1,2000);
v_num NUMBER;
v_sql_text ora_name_list_t;
procedure track(p_text in varchar2) is
begin
insert into .... values (p_text);
end;
begin
v_stack := translate(v_stack,'''','"');
track(v_stack);
v_back := translate(v_back,'''','"');
if v_back is not null then track(v_back); end if;
v_num := ora_sql_txt(v_sql_text);
BEGIN
FOR i IN 1..v_num LOOP
track(to_char(i,'0000')||':'||v_sql_text(i));
END LOOP;
EXCEPTION
WHEN VALUE_ERROR THEN NULL;
END;
end;
In my own environment, I actually have 'TRACK' as a separate procedure that uses an autonomous transaction, rather than a block as above.
create or replace procedure track (p_text IN VARCHAR2) IS
PRAGMA AUTONOMOUS_TRANSACTION;
cursor c_user is
select sys_context('USERENV','CLIENT_INFO') client_info,
sys_context('USERENV','CURRENT_SCHEMA') curr_schema,
sys_context('USERENV','CURRENT_USER') curr_user,
sys_context('USERENV','DB_NAME') db_name,
sys_context('USERENV','HOST') host,
sys_context('USERENV','IP_ADDRESS') ip,
sys_context('USERENV','OS_USER') osuser,
sys_context('USERENV','SESSIONID') sessid,
sys_context('USERENV','SESSION_USER') sess_user,
sys_context('USERENV','TERMINAL') terminal
from dual;
user_rec c_user%rowtype;
v_mod VARCHAR2(48);
v_act VARCHAR2(32);
v_cli_info varchar2(64);
begin
open c_user;
fetch c_user into user_rec;
close c_user;
DBMS_APPLICATION_INFO.READ_MODULE (v_mod, v_act);
--DBMS_APPLICATION_INFO.READ_CLIENT_INFO(v_cli_info);
insert into track_detail
(id, track_time, detail, client_info, curr_schema, curr_user, db_name,
host, ip, osuser, sessid, sess_user, terminal, module, action)
values (track_seq.nextval, systimestamp, p_text,
user_rec.client_info, user_rec.curr_schema, user_rec.curr_user,
user_rec.db_name, user_rec.host, user_rec.ip,
user_rec.osuser, user_rec.sessid, user_rec.sess_user,
user_rec.terminal, v_mod, v_act);
commit;
end;
You can do this with a system trigger.
I directly copied this code from http://www.psoug.org/reference/system_trigger.html.
CREATE TABLE servererror_log (
error_datetime TIMESTAMP,
error_user VARCHAR2(30),
db_name VARCHAR2(9),
error_stack VARCHAR2(2000),
captured_sql VARCHAR2(1000));
CREATE OR REPLACE TRIGGER log_server_errors
AFTER SERVERERROR
ON DATABASE
DECLARE
captured_sql VARCHAR2(1000);
BEGIN
SELECT q.sql_text
INTO captured_sql
FROM gv$sql q, gv$sql_cursor c, gv$session s
WHERE s.audsid = audsid
AND s.prev_sql_addr = q.address
AND q.address = c.parent_handle;
INSERT INTO servererror_log
(error_datetime, error_user, db_name,
error_stack, captured_sql)
VALUES
(systimestamp, sys.login_user, sys.database_name,
dbms_utility.format_error_stack, captured_sql);
END log_server_errors;
/