@@ -39,57 +39,85 @@ create or replace package body ut_coverage is
3939 return l_result;
4040 end;
4141
42+ -- The source query has two important transformations done in it.
43+ -- the flag: to_be_skipped ='Y' is set for a line of code that is badly reported by DBMS_PROFILER as executed 0 times.
44+ -- This includes lines that are:
45+ -- - PACKAGE, PROCEDURE, FUNCTION definition line,
46+ -- - BEGIN, END of a block
47+ -- Another transformation is adjustment of line number for TRIGGER body.
48+ -- DBMS_PROFILER is reporting line numbers for triggers not as defined in DBA_SOURCE, its usign line numbers as defined in DBA_TRIGGERS
49+ -- the DBA_TRIGGERS does not contain the trigger specification lines, only lines that define the trigger body.
50+ -- the query adjusts the line numbers for triggers by finding first occurrence of begin|declare|compound in the trigger body line.
51+ -- The subquery is optimized by:
52+ -- - COALESCE function -> it will execute only for TRIGGERS
53+ -- - scalar subquery cache -> it will only execute once for one trigger source code.
4254 function get_sources_query return varchar2 is
4355 l_result varchar2(32767);
56+ l_full_name varchar2(100);
4457 begin
45- l_result := 'insert /*+ append */ into ut_coverage_sources_tmp(full_name,owner,name,line,text, to_be_skipped)';
4658 if g_file_mappings is not null then
47- l_result := 'insert /*+ append */ into ut_coverage_sources_tmp(full_name,owner,name,line,text, to_be_skipped)
48- select f.file_name, s.owner,s.name,s.line,s.text,';
59+ l_full_name := 'f.file_name';
4960 else
50- l_result := 'insert /*+ append */ into ut_coverage_sources_tmp(full_name,owner,name,line,text, to_be_skipped)
51- select lower(s.owner||''.''||s.name) as file_name, s.owner,s.name,s.line,s.text,';
61+ l_full_name := 'lower(s.owner||''.''||s.name)';
5262 end if;
53- l_result := l_result || q'[
54- case
55- when
56- -- to avoid execution of regexp_like on every line
57- -- first do a rough check for existence of search pattern keyword
58- (lower(s.text) like '%procedure%'
59- or lower(s.text) like '%function%'
60- or lower(s.text) like '%begin%'
61- or lower(s.text) like '%end%'
62- or lower(s.text) like '%package%'
63- ) and
64- regexp_like(
65- s.text,
66- '^\s*(((not)?\s*(overriding|final|instantiable)\s*)*(static|constructor|member)?\s*(procedure|function)|package(\s+body)|begin|end(\s+\S+)?\s*;)', 'i'
67- )
68- then 'Y'
69- end as to_be_skipped
70- from all_source s]';
63+ l_result := '
64+ insert /*+ append */ into ut_coverage_sources_tmp(full_name,owner,name,line,text, to_be_skipped)
65+ select *
66+ from (
67+ select '||l_full_name||q'[,
68+ s.owner,
69+ s.name,
70+ s.line -
71+ coalesce(
72+ case when type!='TRIGGER' then 0 end,
73+ (select min(t.line) - 1
74+ from dba_source t
75+ where t.owner = s.owner and t.type = s.type and t.name = s.name
76+ and regexp_like( t.text, '\w*(begin|declare|compound).*','i'))
77+ ) as line,
78+ s.text,
79+ case
80+ when
81+ -- to avoid execution of regexp_like on every line
82+ -- first do a rough check for existence of search pattern keyword
83+ (lower(s.text) like '%procedure%'
84+ or lower(s.text) like '%function%'
85+ or lower(s.text) like '%begin%'
86+ or lower(s.text) like '%end%'
87+ or lower(s.text) like '%package%'
88+ ) and
89+ regexp_like(
90+ s.text,
91+ '^\s*(((not)?\s*(overriding|final|instantiable)\s*)*(static|constructor|member)?\s*(procedure|function)|package(\s+body)|begin|end(\s+\S+)?\s*;)', 'i'
92+ )
93+ then 'Y'
94+ end as to_be_skipped
95+ from all_source s]';
7196 if g_file_mappings is not null then
7297 l_result := l_result || '
73- join table(:g_file_mappings) f
74- on s.name = f.object_name
75- and s.type = f.object_type
76- and s.owner = f.object_owner
77- where 1 = 1';
98+ join table(:g_file_mappings) f
99+ on s.name = f.object_name
100+ and s.type = f.object_type
101+ and s.owner = f.object_owner
102+ where 1 = 1';
78103 else
79104 l_result := l_result || '
80- where s.owner in (select upper(t.column_value) from table(:l_schema_names) t)';
105+ where s.owner in (select upper(t.column_value) from table(:l_schema_names) t)';
81106 end if;
82107 l_result := l_result || q'[
83- and s.type not in ('PACKAGE', 'TYPE')
84- --Exclude calls to utPLSQL framework, Unit Test packages and objects from a_exclude_list parameter of coverage reporter
85- and (s.owner, s.name) not in (select el.owner, el.name from table(:l_skipped_objects) el)]';
108+ and s.type not in ('PACKAGE', 'TYPE')
109+ --Exclude calls to utPLSQL framework, Unit Test packages and objects from a_exclude_list parameter of coverage reporter
110+ and (s.owner, s.name) not in (select el.owner, el.name from table(:l_skipped_objects) el)]';
86111 if g_include_list is null then
87112 l_result := l_result || '
88- and :g_include_list is null';
113+ and :g_include_list is null';
89114 else
90115 l_result := l_result || '
91- and (s.owner, s.name) in (select il.owner, il.name from table(:g_include_list) il)';
116+ and (s.owner, s.name) in (select il.owner, il.name from table(:g_include_list) il)';
92117 end if;
118+ l_result := l_result || '
119+ )
120+ where line > 0';
93121 return l_result;
94122 end;
95123 /**
0 commit comments