Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 41b4849

Browse files
committed
Fixed issues with framework accessing wrong tables when running self-test.
the TMP table for coverage is now always accessed from package with authid DEFINER.
1 parent c960d44 commit 41b4849

8 files changed

Lines changed: 212 additions & 133 deletions

source/core/coverage/ut_coverage.pkb

Lines changed: 74 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -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

source/core/coverage/ut_coverage_helper.pkb

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@ create or replace package body ut_coverage_helper is
7777
dbms_profiler.stop_profiler();
7878
end;
7979

80-
function get_raw_coverage_data(a_object_owner varchar2, a_object_name varchar2) return unit_line_calls is
80+
function get_raw_coverage_data(a_object_owner varchar2, a_object_name varchar2) return t_unit_line_calls is
8181
type coverage_row is record (
8282
line binary_integer,
8383
calls number(38,0)
8484
);
8585
type coverage_rows is table of coverage_row;
8686
l_tmp_data coverage_rows;
87-
l_results unit_line_calls;
87+
l_results t_unit_line_calls;
8888
begin
8989
select d.line#,
9090
-- This transformation addresses two issues:
@@ -112,9 +112,62 @@ create or replace package body ut_coverage_helper is
112112

113113
procedure mock_coverage_id(a_coverage_id integer) is
114114
begin
115-
if g_develop_mode and g_is_started then
116-
g_coverage_id := a_coverage_id;
117-
end if;
115+
g_develop_mode := true;
116+
g_is_started := true;
117+
g_coverage_id := a_coverage_id;
118+
end;
119+
120+
procedure insert_into_tmp_table(a_data t_coverage_sources_tmp_rows) is
121+
begin
122+
forall i in 1 .. a_data.count
123+
insert into ut_coverage_sources_tmp
124+
(full_name,owner,name,line,text, to_be_skipped)
125+
values(a_data(i).full_name,a_data(i).owner,a_data(i).name,a_data(i).line,a_data(i).text,a_data(i).to_be_skipped);
126+
end;
127+
128+
procedure cleanup_tmp_table is
129+
pragma autonomous_transaction;
130+
begin
131+
null;
132+
execute immediate 'truncate table ut_coverage_sources_tmp$';
133+
commit;
134+
end;
135+
136+
function is_tmp_table_populated return boolean is
137+
l_result integer;
138+
begin
139+
select 1 into l_result from ut_coverage_sources_tmp where rownum = 1;
140+
return (l_result = 1);
141+
exception
142+
when no_data_found then
143+
return false;
144+
end;
145+
146+
function get_tmp_table_objects_cursor return t_tmp_table_objects_crsr is
147+
l_result t_tmp_table_objects_crsr;
148+
begin
149+
open l_result for
150+
select o.owner, o.name, o.full_name, max(o.line) lines_count,
151+
cast(
152+
collect(decode(to_be_skipped, 'Y', to_char(line))) as ut_varchar2_list
153+
) to_be_skipped_list
154+
from ut_coverage_sources_tmp o
155+
group by o.owner, o.name, o.full_name;
156+
157+
return l_result;
158+
end;
159+
160+
function get_tmp_table_object_lines(a_owner varchar2, a_object_name varchar2) return ut_varchar2_list is
161+
l_result ut_varchar2_list;
162+
begin
163+
select rtrim(s.text,chr(10)) text
164+
bulk collect into l_result
165+
from ut_coverage_sources_tmp s
166+
where s.owner = a_owner
167+
and s.name = a_object_name
168+
order by s.line;
169+
170+
return l_result;
118171
end;
119172

120173
end;

source/core/coverage/ut_coverage_helper.pks

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,28 @@ create or replace package ut_coverage_helper authid definer is
1818

1919
--table of line calls indexed by line number
2020
--!!! this table is sparse!!!
21-
type unit_line_calls is table of number(38,0) index by binary_integer;
21+
type t_unit_line_calls is table of number(38,0) index by binary_integer;
22+
23+
type t_coverage_sources_tmp_row is record (
24+
full_name ut_coverage_sources_tmp.full_name%type,
25+
owner ut_coverage_sources_tmp.owner%type,
26+
name ut_coverage_sources_tmp.name%type,
27+
line ut_coverage_sources_tmp.line%type,
28+
to_be_skipped ut_coverage_sources_tmp.to_be_skipped%type,
29+
text ut_coverage_sources_tmp.text%type
30+
);
31+
32+
type t_coverage_sources_tmp_rows is table of t_coverage_sources_tmp_row;
33+
34+
type t_tmp_table_object is record(
35+
owner ut_coverage_sources_tmp.owner%type,
36+
name ut_coverage_sources_tmp.name%type,
37+
full_name ut_coverage_sources_tmp.full_name%type,
38+
lines_count integer,
39+
to_be_skipped_list ut_varchar2_list
40+
);
41+
42+
type t_tmp_table_objects_crsr is ref cursor return t_tmp_table_object;
2243

2344
function is_develop_mode return boolean;
2445

@@ -37,12 +58,23 @@ create or replace package ut_coverage_helper authid definer is
3758

3859
procedure coverage_resume;
3960

40-
function get_raw_coverage_data(a_object_owner varchar2, a_object_name varchar2) return unit_line_calls;
61+
function get_raw_coverage_data(a_object_owner varchar2, a_object_name varchar2) return t_unit_line_calls;
4162

4263
/***
4364
* Allows overwriting of private global variable g_coverage_id
4465
* Used internally, only for unit testing of the framework only
4566
*/
4667
procedure mock_coverage_id(a_coverage_id integer);
68+
69+
procedure insert_into_tmp_table(a_data t_coverage_sources_tmp_rows);
70+
71+
procedure cleanup_tmp_table;
72+
73+
function is_tmp_table_populated return boolean;
74+
75+
function get_tmp_table_objects_cursor return t_tmp_table_objects_crsr;
76+
77+
function get_tmp_table_object_lines(a_owner varchar2, a_object_name varchar2) return ut_varchar2_list;
78+
4779
end;
4880
/

source/core/ut_utils.pkb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,12 +340,12 @@ create or replace package body ut_utils is
340340
end if;
341341
return l_result;
342342
end;
343-
343+
344344
procedure set_action(a_text in varchar2) is
345345
begin
346346
dbms_application_info.set_module('utPLSQL', a_text);
347347
end;
348-
348+
349349
procedure set_client_info(a_text in varchar2) is
350350
begin
351351
dbms_application_info.set_client_info(a_text);
@@ -381,7 +381,6 @@ create or replace package body ut_utils is
381381
pragma autonomous_transaction;
382382
begin
383383
execute immediate 'truncate table ut_cursor_data';
384-
execute immediate 'truncate table ut_coverage_sources_tmp$';
385384
commit;
386385
end;
387386

source/create_synonyms_and_grants_for_public.sql

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ grant execute on &&ut3_owner..ut_reporter_base to public;
5959
grant execute on &&ut3_owner..ut_coverage to public;
6060
grant execute on &&ut3_owner..ut_coverage_options to public;
6161
grant execute on &&ut3_owner..ut_coverage_helper to public;
62-
grant insert, delete, select on &&ut3_owner..ut_coverage_sources_tmp to public;
6362
grant execute on &&ut3_owner..ut_output_buffer to public;
6463
grant execute on &&ut3_owner..ut_file_mappings to public;
6564
grant execute on &&ut3_owner..ut_file_mapping to public;
@@ -99,7 +98,6 @@ create public synonym ut_reporter_base for &&ut3_owner..ut_reporter_base;
9998
create public synonym ut_coverage for &&ut3_owner..ut_coverage;
10099
create public synonym ut_coverage_options for &&ut3_owner..ut_coverage_options;
101100
create public synonym ut_coverage_helper for &&ut3_owner..ut_coverage_helper;
102-
create public synonym ut_coverage_sources_tmp for &&ut3_owner..ut_coverage_sources_tmp;
103101
create public synonym ut_output_buffer for &&ut3_owner..ut_output_buffer;
104102
create public synonym ut_file_mappings for &&ut3_owner..ut_file_mappings;
105103
create public synonym ut_file_mapping for &&ut3_owner..ut_file_mapping;

0 commit comments

Comments
 (0)