LarrySteele
Programmer
I built script to load a table using the bulk collect...for all...save exceptions method. My exceptions statement handled the DML errors just fine. Then I added and added to the script. Even though I tested at each add, apparently I forgot to test when we have DML errors until last night. I've gone through my script and I've verified through numerous websites that my logic *appears* sound. Nevertheless, when I toss in data that will cause a DML error, the error is not recognized as DML and is identified as OTHERS.
Here's the complete script, in its entirety:
In the first iteration of this script (of course, that's nowhere to be found), I could inject a DML error by changing the country code for select records so a code with four characters (this is a varchar2(3) field). That would be recognized as a DML error and would go through the DML error handler to record the error.
I'd appreciate any assistance in getting Oracle to recognize my DML errors as DML errors.
Larry
Here's the complete script, in its entirety:
Code:
set feedback off;
set verify off;
set serveroutput on size 1000000;
-- set parameters...
def schem = 'HRTDMART';
def tbl = 'EE_COUNTRY';
def scrpt = 'INSERT_EE_COUNTRY.SQL';
def dep_tbl = 'TABLE01'',''EE_LOC_CODE'',''EE_HOME';
def dep_cnt = 3;
def key1 = 'PERSID';
declare
-- table
type sap_tab is table of &&schem..&&tbl.%rowtype;
sap_tbl sap_tab := sap_tab();
-- cursor so we can batch load our collection
cursor csr_data is
select p.persid,
case when el.mail_site is null then eh.home_country
when el.mail_site = 'FS' then eh.home_country
when el.mail_site = '99' then substr(el.loc_code,3,2)
else 'US' end as country_code
from &&schem..pa0001 p,
&&schem..ee_loc_code el,
&&schem..ee_home eh
where el.persid=p.persid
and eh.persid=p.persid;
-- common variables
dep_bad_load number :=1;
dep_loads number :=0;
error_cnt number :=0;
error_cnt1 number :=0;
error_idx number;
error_code number;
error_desc varchar2(600 char);
error_stats number :=0;
row_cnt number :=0;
bad_load varchar2(1 char) := 'N';
dml_errors exception;
pragma exception_init(dml_errors, -24381);
time_start number := dbms_utility.get_time;
time_stop number;
time_total varchar2(20 char);
script_name varchar2(50 char) := '&&scrpt';
table_name varchar2(50 char) := '&&tbl';
begin
-- check the tables we depend on...
select sum(bad_load),
sum(loads)
into dep_bad_load,
dep_loads
from (
select case bad_load when 'N' then 0 else 1 end bad_load,
1 loads
from &&schem..hrdm_load_stats
where load_date = to_date(sysdate)
and table_name in ('&&dep_tbl'));
if nvl(dep_bad_load,0) != 0 or nvl(dep_loads,0) != &&dep_cnt then -- source table problem
-- record bad load stat and error for this table
insert into &&schem..hrdm_load_stats
(
script_name,
table_name,
insert_count,
error_count,
bad_load,
load_date,
load_time
)
values
(
script_name,
table_name,
0,
0,
'Y',
to_date(sysdate),
to_char(sysdate, 'hh24:mi:ss')
);
insert into &&schem..hrdm_load_errors
(
script_name,
table_name,
error_code,
error_desc,
key_data,
load_date
)
values
(
script_name,
table_name,
'-20002',
'ORA-20002: TABLE LOAD HOLD FOR ' || table_name,
'',
to_date(sysdate)
);
-- raise user defined error
raise_application_error (-20002, 'TABLE LOAD HOLD FOR ' || table_name);
end if;
begin
-- if we make it here, our source tables loaded okay
execute immediate 'truncate table &&schem..&&tbl';
-- bulk collect (loads into memory) from cursor
open csr_data;
loop
fetch csr_data
bulk collect into sap_tbl limit 25000;
exit when sap_tbl.count = 0;
-- forall (bulk save from memory into our table) recording exceptions if they occur
forall i in sap_tbl.first..sap_tbl.last save exceptions
insert into &&schem..&&tbl values sap_tbl(i);
-- keep track of rows inserted
row_cnt := row_cnt + sql%rowcount; -- just in case we didn't have an error
end loop;
close csr_data;
exception
-- record individual record errors in the load_errors table
when dml_errors then
row_cnt := sql%rowcount; -- pick up the rowcount from last process sql (forall...)
error_cnt := sql%bulk_exceptions.count;
error_cnt1 := error_cnt1 + error_cnt;
for e in 1..25 loop --error_cnt loop
error_idx := sql%bulk_exceptions(e).error_index;
error_code := sql%bulk_exceptions(e).error_code;
error_desc := sqlerrm(-error_code);
insert into &&schem..hrdm_load_errors
(
script_name,
table_name,
error_code,
error_desc,
key_data,
load_date
)
values
(
script_name,
table_name,
to_char(-error_code),
error_desc,
'PERSID: "' || sap_tbl(error_idx).PERSID || '"',
to_date(sysdate)
);
end loop;
when others then
--null;
bad_load := 'Y'; -- unexpected/unhandled error: bad load to investigate
end;
-- process load stats
select count(1)
into row_cnt
from &&schem..&&tbl.;
if row_cnt > 0 then
error_stats := (error_cnt / row_cnt) * 100;
else
error_stats := 100; -- if no rows inserted, then 100% load failure
end if;
if error_stats > 10 then -- more than 10% failed to load
bad_load := 'Y';
end if;
insert into &&schem..hrdm_load_stats
(
script_name,
table_name,
insert_count,
error_count,
bad_load,
load_date,
load_time
)
values
(
script_name,
table_name,
row_cnt,
error_cnt,
bad_load,
to_date(sysdate),
to_char(sysdate, 'hh24:mi:ss')
);
commit;
time_stop := dbms_utility.get_time;
time_total := to_char((time_stop - time_start)/100);
-- post user defined error (if it occurs) to the screen for review.
-- otherwise post results to the screen for review
begin
if bad_load = 'Y' then
raise_application_error (-20001, 'BAD LOAD ERROR FOR ' || table_name);
else
dbms_output.put_line(script_name || ' loaded. ' ||
row_cnt || ' rows inserted - ' ||
error_cnt1 || ' errors.');
end if;
exception
when others then
if to_char(sqlcode) = -20001 then
-- our error code
dbms_output.put_line(sqlerrm);
else
-- some other error occured...
dbms_output.put_line(script_name || ' LOAD ERROR: ' || to_char(sqlcode) || '-' || sqlerrm);
end if;
end;
exception
when others then
if to_char(sqlcode) = -20002 then
-- our error code
dbms_output.put_line(sqlerrm);
else
-- some other error occured...
dbms_output.put_line(script_name || ' LOAD ERROR: ' || to_char(sqlcode) || '-' || sqlerrm);
end if;
end;
/
In the first iteration of this script (of course, that's nowhere to be found), I could inject a DML error by changing the country code for select records so a code with four characters (this is a varchar2(3) field). That would be recognized as a DML error and would go through the DML error handler to record the error.
I'd appreciate any assistance in getting Oracle to recognize my DML errors as DML errors.
Larry