create a table function
create function catch_exceptions_blocks(program_name varchar2,v_type varchar2:='PACKAGE BODY')
return sys.odciVarchar2List pipelined
IS
code_ clob;
amount binary_integer;
offset integer;
first_row varchar2(32767);
more_rows varchar2(32767);
exception_row varchar2(32767);
start_string varchar2(9):= 'EXCEPTION'; -- start of the block
end_string varchar2(4):='END;'; -- end of the block
function clean_tokens(v_string in varchar2)
return varchar2
is
v_x varchar2(100);
v_new varchar2(1000):=v_string;
type tokens is table of varchar2(100) INDEX BY PLS_INTEGER; -- create table of type array to hold the token
t_tokens tokens;
begin
for i in 1..regexp_count(v_string,'\$#{') loop
-- get only token $#{line number}#$
v_x := substr(v_string,instr(v_string,'$#{',1,i),instr(v_string,'}#$',1,i)+3-instr(v_string,'$#{',1,i));
t_tokens(i) := v_x;
end loop;
for i in 1..t_tokens.count
loop
v_new := replace(v_new,t_tokens(i)); -- remove the token from string
end loop;
t_tokens.delete;
return v_new;
end;
BEGIN
-- create temporary lob to hold source code from user_source table
--to make it easier to catch the exceptions
DBMS_LOB.CREATETEMPORARY(code_,true, DBMS_LOB.SESSION);
for rec in
(
select
name,
type,
line,
upper(regexp_replace(text, ' +', ' ')) text
from user_source
where name = upper(program_name)
and type = upper(v_type)
)
loop
if rec.line = 1 then
first_row := '$#{'||rec.line||'}#$'||rec.text; -- number of line inside $#{ }#$
amount := length(first_row);
offset := 1;
DBMS_LOB.WRITE(code_, amount, offset, first_row);
else
more_rows := '$#{'||rec.line||'}#$'||rec.text;
DBMS_LOB.WRITEAPPEND(code_, length(more_rows), more_rows);
end if;
end loop;
-- iterate the number of occurrences of the word EXCEPTION
for i in 1..regexp_count(code_,start_string)
loop
-- use REPLACE CHR(10) to put everything on one row,
-- and DBMS_LOB.SUBSTR and DBMS_LOB.INSTR to catch the block EXCEPTION using i as occurrence number
exception_row := replace(DBMS_LOB.SUBSTR(code_ ,instr(DBMS_LOB.SUBSTR(code_,1000,
DBMS_LOB.INSTR(code_,start_string,1,i)),end_string)+
LENGTH(end_string)-1,DBMS_LOB.INSTR (code_,start_string,1,i)),CHR(10));
if clean_tokens(exception_row) like 'EXCEPTION WHEN%'
THEN --use function to ensure that we only want the exception block
pipe row (replace(replace(exception_row,'$#{',' (') , '}#$',')'));-- replace $#{ and }#$ with ( and ) to stay more readable
end if;
end loop;
DBMS_LOB.FREETEMPORARY(code_);
return;
exception when others then
DBMS_LOB.FREETEMPORARY(code_);
DBMS_OUTPUT.PUT_LINE(sqlerrm);
end;