@@ -30,7 +30,7 @@ create or replace package body ut_coverage is
3030 -- The subquery is optimized by:
3131 -- - COALESCE function -> it will execute only for TRIGGERS
3232 -- - scalar subquery cache -> it will only execute once for one trigger source code.
33- function get_populate_sources_tmp_sql (a_coverage_options ut_coverage_options) return varchar2 is
33+ function get_cov_sources_sql (a_coverage_options ut_coverage_options) return varchar2 is
3434 l_result varchar2(32767);
3535 l_full_name varchar2(100);
3636 l_view_name varchar2(200) := ut_metadata.get_dba_view('dba_source');
@@ -41,10 +41,9 @@ create or replace package body ut_coverage is
4141 l_full_name := 'lower(s.owner||''.''||s.name)';
4242 end if;
4343 l_result := '
44- insert /*+ append */ into ut_coverage_sources_tmp(full_name,owner,name,line,text, to_be_skipped)
45- select *
44+ select full_name, owner, name, line, to_be_skipped, text
4645 from (
47- select '||l_full_name||q'[,
46+ select '||l_full_name||q'[ as full_name ,
4847 s.owner,
4948 s.name,
5049 s.line -
@@ -101,26 +100,46 @@ create or replace package body ut_coverage is
101100 return l_result;
102101 end;
103102
104- function is_tmp_table_populated return boolean is
105- l_result integer;
103+ function get_cov_sources_cursor(a_coverage_options ut_coverage_options) return sys_refcursor is
104+ l_cursor sys_refcursor;
105+ l_skip_objects ut_object_names;
106+ l_schema_names ut_varchar2_rows;
107+ l_sql varchar2(32767);
106108 begin
107- select 1 into l_result from ut_coverage_sources_tmp where rownum = 1;
108- return (l_result = 1);
109- exception
110- when no_data_found then
111- return false;
109+ l_schema_names := coalesce(a_coverage_options.schema_names, ut_varchar2_rows(sys_context('USERENV','CURRENT_SCHEMA')));
110+ if not ut_coverage_helper.is_develop_mode() then
111+ --skip all the utplsql framework objects and all the unit test packages that could potentially be reported by coverage.
112+ l_skip_objects := ut_utils.get_utplsql_objects_list() multiset union all coalesce(a_coverage_options.exclude_objects, ut_object_names());
113+ end if;
114+ l_sql := get_cov_sources_sql(a_coverage_options);
115+ if a_coverage_options.file_mappings is not empty then
116+ open l_cursor for l_sql using a_coverage_options.file_mappings, l_skip_objects, a_coverage_options.include_objects;
117+ else
118+ open l_cursor for l_sql using l_schema_names, l_skip_objects, a_coverage_options.include_objects;
119+ end if;
120+ return l_cursor;
112121 end;
113122
114- procedure populate_tmp_table(a_coverage_options ut_coverage_options, a_skipped_objects ut_object_names ) is
123+ procedure populate_tmp_table(a_coverage_options ut_coverage_options) is
115124 pragma autonomous_transaction;
116- l_schema_names ut_varchar2_rows;
125+ l_cov_sources_crsr sys_refcursor;
126+ l_cov_sources_data ut_coverage_helper.t_coverage_sources_tmp_rows;
117127 begin
118- delete from ut_coverage_sources_tmp;
119- l_schema_names := coalesce(a_coverage_options.schema_names, ut_varchar2_rows(sys_context('USERENV','CURRENT_SCHEMA')));
120- if a_coverage_options.file_mappings is not empty then
121- execute immediate get_populate_sources_tmp_sql(a_coverage_options) using a_coverage_options.file_mappings, a_skipped_objects, a_coverage_options.include_objects;
122- else
123- execute immediate get_populate_sources_tmp_sql(a_coverage_options) using l_schema_names, a_skipped_objects, a_coverage_options.include_objects;
128+
129+ if not ut_coverage_helper.is_tmp_table_populated() or ut_coverage_helper.is_develop_mode() then
130+ ut_coverage_helper.cleanup_tmp_table();
131+
132+ l_cov_sources_crsr := get_cov_sources_cursor(a_coverage_options);
133+
134+ loop
135+ fetch l_cov_sources_crsr bulk collect into l_cov_sources_data limit 1000;
136+
137+ ut_coverage_helper.insert_into_tmp_table(l_cov_sources_data);
138+
139+ exit when l_cov_sources_crsr%notfound;
140+ end loop;
141+
142+ close l_cov_sources_crsr;
124143 end if;
125144 commit;
126145 end;
@@ -159,94 +178,80 @@ create or replace package body ut_coverage is
159178 ut_coverage_helper.coverage_stop_develop();
160179 end;
161180
162- function get_lines_to_skip(a_object_owner varchar2, a_object_name varchar2) return t_source_lines is
163- l_result t_source_lines;
164- begin
165- select line
166- bulk collect into l_result
167- from ut_coverage_sources_tmp o
168- where to_be_skipped = 'Y'
169- and o.owner = a_object_owner
170- and o.name = a_object_name;
171-
172- return l_result;
173- end;
174-
175181 function get_coverage_data(a_coverage_options ut_coverage_options) return t_coverage is
176- l_line_calls ut_coverage_helper.unit_line_calls ;
177- l_result t_coverage;
178- l_new_unit t_unit_coverage;
179- l_skipped_objects ut_object_names := ut_object_names() ;
180- l_lines_to_skip t_source_lines ;
181- line_no binary_integer ;
182+ l_line_calls ut_coverage_helper.t_unit_line_calls ;
183+ l_result t_coverage;
184+ l_new_unit t_unit_coverage;
185+ line_no binary_integer ;
186+ l_source_objects_crsr ut_coverage_helper.t_tmp_table_objects_crsr ;
187+ l_source_object ut_coverage_helper.t_tmp_table_object ;
182188 begin
183189
184- if not ut_coverage_helper.is_develop_mode() then
185- --skip all the utplsql framework objects and all the unit test packages that could potentially be reported by coverage.
186- l_skipped_objects := ut_utils.get_utplsql_objects_list() multiset union all coalesce(a_coverage_options.exclude_objects, ut_object_names());
187- end if;
188-
189190 --prepare global temp table with sources
190- if not is_tmp_table_populated() or ut_coverage_helper.is_develop_mode() then
191- populate_tmp_table(a_coverage_options, l_skipped_objects);
192- end if;
191+ populate_tmp_table(a_coverage_options);
193192
194- for src_object in (
195- select o.owner, o.name, o.full_name, max(o.line) lines_count
196- from ut_coverage_sources_tmp o
197- group by o.owner, o.name, o.full_name
198- ) loop
199-
200- l_lines_to_skip := get_lines_to_skip( src_object.owner, src_object.name );
193+ l_source_objects_crsr := ut_coverage_helper.get_tmp_table_objects_cursor();
194+ loop
195+ fetch l_source_objects_crsr into l_source_object;
196+ exit when l_source_objects_crsr%notfound;
201197
202198 --get coverage data
203- l_line_calls := ut_coverage_helper.get_raw_coverage_data( src_object .owner, src_object .name );
199+ l_line_calls := ut_coverage_helper.get_raw_coverage_data( l_source_object .owner, l_source_object .name );
204200
205201 --if there is coverage, we need to filter out the garbage (badly indicated data from dbms_profiler)
206202 if l_line_calls.count > 0 then
207203 --remove lines that should not be indicted as meaningful
208- for i in 1 .. l_lines_to_skip.count loop
209- l_line_calls.delete(l_lines_to_skip(i));
204+ for i in 1 .. l_source_object.to_be_skipped_list.count loop
205+ if l_source_object.to_be_skipped_list(i) is not null then
206+ l_line_calls.delete(l_source_object.to_be_skipped_list(i));
207+ end if;
210208 end loop;
211209 end if;
212210
213211 --if there are no file mappings or object was actually captured by profiler
214212 if a_coverage_options.file_mappings is null or l_line_calls.count > 0 then
215- if not l_result.objects.exists(src_object.full_name) then
216- l_result.objects(src_object.full_name) := l_new_unit;
217- l_result.objects(src_object.full_name).owner := src_object.owner;
218- l_result.objects(src_object.full_name).name := src_object.name;
213+
214+ --populate total stats
215+ l_result.total_lines := l_result.total_lines + l_source_object.lines_count;
216+
217+ --populate object level coverage stats
218+ if not l_result.objects.exists(l_source_object.full_name) then
219+ l_result.objects(l_source_object.full_name) := l_new_unit;
220+ l_result.objects(l_source_object.full_name).owner := l_source_object.owner;
221+ l_result.objects(l_source_object.full_name).name := l_source_object.name;
222+ l_result.objects(l_source_object.full_name).total_lines := l_source_object.lines_count;
219223 end if;
220- l_result.total_lines := l_result.total_lines + src_object.lines_count;
221- l_result.objects(src_object.full_name).total_lines := src_object.lines_count;
222224 --map to results
223225 line_no := l_line_calls.first;
224226 if line_no is null then
225- l_result.uncovered_lines := l_result.uncovered_lines + src_object .lines_count;
226- l_result.objects(src_object .full_name).uncovered_lines := src_object .lines_count;
227+ l_result.uncovered_lines := l_result.uncovered_lines + l_source_object .lines_count;
228+ l_result.objects(l_source_object .full_name).uncovered_lines := l_source_object .lines_count;
227229 else
228230 loop
229231 exit when line_no is null;
230232
231233 if l_line_calls(line_no) > 0 then
234+ --total stats
232235 l_result.covered_lines := l_result.covered_lines + 1;
233236 l_result.executions := l_result.executions + l_line_calls(line_no);
234- l_result.objects(src_object.full_name).covered_lines := l_result.objects(src_object.full_name).covered_lines + 1;
235- l_result.objects(src_object.full_name).executions := l_result.objects(src_object.full_name).executions + l_line_calls(line_no);
237+ --object level stats
238+ l_result.objects(l_source_object.full_name).covered_lines := l_result.objects(l_source_object.full_name).covered_lines + 1;
239+ l_result.objects(l_source_object.full_name).executions := l_result.objects(l_source_object.full_name).executions + l_line_calls(line_no);
236240 elsif l_line_calls(line_no) = 0 then
237241 l_result.uncovered_lines := l_result.uncovered_lines + 1;
238- l_result.objects(src_object .full_name).uncovered_lines := l_result.objects(src_object .full_name).uncovered_lines + 1;
242+ l_result.objects(l_source_object .full_name).uncovered_lines := l_result.objects(l_source_object .full_name).uncovered_lines + 1;
239243 end if;
240- l_result.objects(src_object .full_name).lines(line_no) := l_line_calls(line_no);
244+ l_result.objects(l_source_object .full_name).lines(line_no) := l_line_calls(line_no);
241245
242246 line_no := l_line_calls.next(line_no);
243247 end loop;
244248 end if;
245249 end if;
246250
247-
248251 end loop;
249252
253+ close l_source_objects_crsr;
254+
250255 return l_result;
251256 end get_coverage_data;
252257
0 commit comments