Skip to content

Feature/framework performance #1249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions source/api/ut.pkb
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,15 @@ create or replace package body ut is
raise_if_packages_invalidated();
raise no_data_found;
end if;
g_result_lines := ut_utils.clob_to_table(l_clob, ut_utils.gc_max_storage_varchar2_len);
g_result_line_no := g_result_lines.first;
if l_clob is not null and l_clob != empty_clob() then
if length(l_clob) > ut_utils.gc_max_storage_varchar2_len then
g_result_lines := ut_utils.clob_to_table(l_clob, ut_utils.gc_max_storage_varchar2_len);
else
g_result_lines := ut_varchar2_list(l_clob);
end if;
g_result_line_no := g_result_lines.first;
end if;
end if;

if g_result_line_no is not null then
l_result := g_result_lines(g_result_line_no);
g_result_line_no := g_result_lines.next(g_result_line_no);
Expand Down Expand Up @@ -273,6 +278,7 @@ create or replace package body ut is
);
if l_reporter is of (ut_output_reporter_base) then
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
g_result_lines := ut_varchar2_list();
loop
pipe row( get_report_outputs( l_results ) );
end loop;
Expand Down Expand Up @@ -320,6 +326,7 @@ create or replace package body ut is
);
if l_reporter is of (ut_output_reporter_base) then
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
g_result_lines := ut_varchar2_list();
loop
pipe row( get_report_outputs( l_results ) );
end loop;
Expand Down Expand Up @@ -368,6 +375,7 @@ create or replace package body ut is
);
if l_reporter is of (ut_output_reporter_base) then
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
g_result_lines := ut_varchar2_list();
loop
pipe row( get_report_outputs( l_results ) );
end loop;
Expand Down Expand Up @@ -416,6 +424,7 @@ create or replace package body ut is
);
if l_reporter is of (ut_output_reporter_base) then
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
g_result_lines := ut_varchar2_list();
loop
pipe row( get_report_outputs( l_results ) );
end loop;
Expand Down Expand Up @@ -464,6 +473,7 @@ create or replace package body ut is
);
if l_reporter is of (ut_output_reporter_base) then
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
g_result_lines := ut_varchar2_list();
loop
pipe row( get_report_outputs( l_results ) );
end loop;
Expand Down Expand Up @@ -512,6 +522,7 @@ create or replace package body ut is
);
if l_reporter is of (ut_output_reporter_base) then
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
g_result_lines := ut_varchar2_list();
loop
pipe row( get_report_outputs( l_results ) );
end loop;
Expand Down
163 changes: 163 additions & 0 deletions source/core/output_buffers/ut_output_bulk_buffer.tpb
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
create or replace type body ut_output_bulk_buffer is
/*
utPLSQL - Version 3
Copyright 2016 - 2023 utPLSQL Project

Licensed under the Apache License, Version 2.0 (the "License"):
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

constructor function ut_output_bulk_buffer(self in out nocopy ut_output_bulk_buffer, a_output_id raw := null) return self as result is
begin
self.init(a_output_id, $$plsql_unit);
return;
end;

overriding member procedure send_line(self in out nocopy ut_output_bulk_buffer, a_text varchar2, a_item_type varchar2 := null) is
pragma autonomous_transaction;
begin
if a_text is not null or a_item_type is not null then
if length(a_text) > ut_utils.gc_max_storage_varchar2_len then
self.send_lines(
ut_utils.convert_collection(
ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len)
),
a_item_type
);
else
self.last_write_message_id := self.last_write_message_id + 1;
insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type)
values (self.output_id, self.last_write_message_id, a_text, a_item_type);
end if;
commit;
end if;
end;

overriding member procedure send_lines(self in out nocopy ut_output_bulk_buffer, a_text_list ut_varchar2_rows, a_item_type varchar2 := null) is
pragma autonomous_transaction;
begin
insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type)
select /*+ no_parallel */ self.output_id, self.last_write_message_id + rownum, t.column_value, a_item_type
from table(a_text_list) t
where t.column_value is not null or a_item_type is not null;
self.last_write_message_id := self.last_write_message_id + sql%rowcount;
commit;
end;

overriding member procedure send_clob(self in out nocopy ut_output_bulk_buffer, a_text clob, a_item_type varchar2 := null) is
pragma autonomous_transaction;
begin
if a_text is not null and a_text != empty_clob() or a_item_type is not null then
if length(a_text) > ut_utils.gc_max_storage_varchar2_len then
self.send_lines(
ut_utils.convert_collection(
ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len)
),
a_item_type
);
else
self.last_write_message_id := self.last_write_message_id + 1;
insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type)
values (self.output_id, self.last_write_message_id, a_text, a_item_type);
end if;
commit;
end if;
end;

overriding member procedure lines_to_dbms_output(self in ut_output_bulk_buffer, a_initial_timeout number := null, a_timeout_sec number := null) is
l_data sys_refcursor;
l_text ut_varchar2_rows;
l_item_type ut_varchar2_rows;
begin
l_data := self.get_lines_cursor(a_initial_timeout, a_timeout_sec);
loop
fetch l_data bulk collect into l_text, l_item_type limit 10000;
for idx in 1 .. l_text.count loop
dbms_output.put_line(l_text(idx));
end loop;
exit when l_data%notfound;
end loop;
close l_data;
self.remove_buffer_info();
end;

overriding member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor is
lc_init_wait_sec constant number := coalesce(a_initial_timeout, 10 );
l_already_waited_sec number(10,2) := 0;
l_sleep_time number(2,1);
l_exists integer;
l_finished boolean := false;
l_data_produced boolean := false;
l_producer_active boolean := false;
l_producer_started boolean := false;
l_producer_finished boolean := false;
l_results sys_refcursor;
begin

while not l_finished loop

if not l_data_produced then
select /*+ no_parallel */ count(1) into l_exists
from ut_output_buffer_tmp o
where o.output_id = self.output_id and rownum = 1;
l_data_produced := (l_exists = 1);
end if;

l_sleep_time := case when l_already_waited_sec >= 1 then 0.5 else 0.1 end;
l_producer_active := (self.get_lock_status() <> 0);
l_producer_started := (l_producer_active or l_data_produced ) or l_producer_started;
l_producer_finished := (l_producer_started and not l_producer_active) or l_producer_finished;
l_finished :=
self.timeout_producer_not_finished(l_producer_finished, l_already_waited_sec, a_timeout_sec)
or self.timeout_producer_not_started(l_producer_started, l_already_waited_sec, lc_init_wait_sec)
or l_producer_finished;

dbms_lock.sleep(l_sleep_time);
l_already_waited_sec := l_already_waited_sec + l_sleep_time;
end loop;

open l_results for
select /*+ no_parallel */ o.text, o.item_type
from ut_output_buffer_tmp o
where o.output_id = self.output_id
and o.text is not null
order by o.output_id, o.message_id;

return l_results;

end;

/* Important note.
This function code is almost duplicated between two types for performance reasons.
The pipe row clause is much faster on VARCHAR2 then it is on clob.
That is the key reason for two implementations.
*/
overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined is
l_data sys_refcursor;
l_text ut_varchar2_rows;
l_item_type ut_varchar2_rows;
begin
l_data := self.get_lines_cursor(a_initial_timeout, a_timeout_sec);
loop
fetch l_data bulk collect into l_text, l_item_type limit 10000;
for idx in 1 .. l_text.count loop
pipe row( ut_output_data_row(l_text(idx), l_item_type(idx)) );
end loop;
exit when l_data%notfound;
end loop;
close l_data;
self.remove_buffer_info();
return;
end;

end;
/
27 changes: 27 additions & 0 deletions source/core/output_buffers/ut_output_bulk_buffer.tps
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
create or replace type ut_output_bulk_buffer under ut_output_buffer_base (
/*
utPLSQL - Version 3
Copyright 2016 - 2023 utPLSQL Project

Licensed under the Apache License, Version 2.0 (the "License"):
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

constructor function ut_output_bulk_buffer(self in out nocopy ut_output_bulk_buffer, a_output_id raw := null) return self as result,
overriding member procedure send_line(self in out nocopy ut_output_bulk_buffer, a_text varchar2, a_item_type varchar2 := null),
overriding member procedure send_lines(self in out nocopy ut_output_bulk_buffer, a_text_list ut_varchar2_rows, a_item_type varchar2 := null),
overriding member procedure send_clob(self in out nocopy ut_output_bulk_buffer, a_text clob, a_item_type varchar2 := null),
overriding member procedure lines_to_dbms_output(self in ut_output_bulk_buffer, a_initial_timeout number := null, a_timeout_sec number := null),
overriding member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor,
overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined
) not final
/
10 changes: 6 additions & 4 deletions source/core/output_buffers/ut_output_table_buffer.tpb
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,16 @@ create or replace type body ut_output_table_buffer is

overriding member procedure lines_to_dbms_output(self in ut_output_table_buffer, a_initial_timeout number := null, a_timeout_sec number := null) is
l_data sys_refcursor;
l_text varchar2(32767);
l_item_type varchar2(32767);
l_text ut_varchar2_rows;
l_item_type ut_varchar2_rows;
begin
l_data := self.get_lines_cursor(a_initial_timeout, a_timeout_sec);
loop
fetch l_data into l_text, l_item_type;
fetch l_data bulk collect into l_text, l_item_type limit 10000;
for idx in 1 .. l_text.count loop
dbms_output.put_line(l_text(idx));
end loop;
exit when l_data%notfound;
dbms_output.put_line(l_text);
end loop;
close l_data;
end;
Expand Down
1 change: 1 addition & 0 deletions source/core/ut_utils.pkb
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ create or replace package body ut_utils is
end loop;
exit when l_lines_data%notfound;
end loop;
close l_lines_data;
execute immediate 'truncate table ut_dbms_output_cache';
commit;
end;
Expand Down
2 changes: 2 additions & 0 deletions source/install.sql
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ create or replace context &&ut3_owner._info using &&ut3_owner..ut_session_contex
@@install_component.sql 'core/output_buffers/ut_output_table_buffer.tpb'
@@install_component.sql 'core/output_buffers/ut_output_clob_table_buffer.tps'
@@install_component.sql 'core/output_buffers/ut_output_clob_table_buffer.tpb'
@@install_component.sql 'core/output_buffers/ut_output_bulk_buffer.tps'
@@install_component.sql 'core/output_buffers/ut_output_bulk_buffer.tpb'

@@install_component.sql 'core/types/ut_output_reporter_base.tps'

Expand Down
2 changes: 1 addition & 1 deletion source/reporters/ut_coverage_cobertura_reporter.tpb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ create or replace type body ut_coverage_cobertura_reporter is
self in out nocopy ut_coverage_cobertura_reporter
) return self as result is
begin
self.init($$plsql_unit);
self.init($$plsql_unit,ut_output_bulk_buffer());
return;
end;

Expand Down
2 changes: 1 addition & 1 deletion source/reporters/ut_coverage_html_reporter.tpb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ create or replace type body ut_coverage_html_reporter is
a_html_report_assets_path varchar2 := null
) return self as result is
begin
self.init($$plsql_unit);
self.init($$plsql_unit,ut_output_bulk_buffer());
self.project_name := a_project_name;
assets_path := nvl(a_html_report_assets_path, ut_coverage_report_html_helper.get_default_html_assets_path());
return;
Expand Down
9 changes: 8 additions & 1 deletion source/reporters/ut_coverage_sonar_reporter.tpb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ create or replace type body ut_coverage_sonar_reporter is
self in out nocopy ut_coverage_sonar_reporter
) return self as result is
begin
self.init($$plsql_unit);
self.init($$plsql_unit,ut_output_bulk_buffer());
return;
end;

Expand Down Expand Up @@ -84,6 +84,12 @@ create or replace type body ut_coverage_sonar_reporter is
end;

begin
-- execute immediate 'alter session set statistics_level=all';
-- dbms_hprof.start_profiling(
-- location => 'PLSHPROF_DIR'
-- , filename => 'profiler_utPLSQL_run_on_'||$$plsql_unit||'_'||rawtohex(self.id)||'.txt'
-- );
--
ut_coverage.coverage_stop();

self.print_text_lines(
Expand All @@ -92,6 +98,7 @@ create or replace type body ut_coverage_sonar_reporter is
a_run
)
);
-- dbms_hprof.stop_profiling;
end;

overriding member function get_description return varchar2 as
Expand Down
2 changes: 1 addition & 1 deletion source/reporters/ut_coveralls_reporter.tpb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ create or replace type body ut_coveralls_reporter is
self in out nocopy ut_coveralls_reporter
) return self as result is
begin
self.init($$plsql_unit);
self.init($$plsql_unit,ut_output_bulk_buffer());
return;
end;

Expand Down
2 changes: 1 addition & 1 deletion source/reporters/ut_junit_reporter.tpb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ create or replace type body ut_junit_reporter is

constructor function ut_junit_reporter(self in out nocopy ut_junit_reporter) return self as result is
begin
self.init($$plsql_unit);
self.init($$plsql_unit,ut_output_bulk_buffer());
return;
end;

Expand Down
2 changes: 1 addition & 1 deletion source/reporters/ut_sonar_test_reporter.tpb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ create or replace type body ut_sonar_test_reporter is
self in out nocopy ut_sonar_test_reporter
) return self as result is
begin
self.init($$plsql_unit);
self.init($$plsql_unit,ut_output_bulk_buffer());
return;
end;

Expand Down
2 changes: 1 addition & 1 deletion source/reporters/ut_tfs_junit_reporter.tpb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ create or replace type body ut_tfs_junit_reporter is

constructor function ut_tfs_junit_reporter(self in out nocopy ut_tfs_junit_reporter) return self as result is
begin
self.init($$plsql_unit);
self.init($$plsql_unit,ut_output_bulk_buffer());
return;
end;

Expand Down
2 changes: 1 addition & 1 deletion source/reporters/ut_xunit_reporter.tpb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ create or replace type body ut_xunit_reporter is

constructor function ut_xunit_reporter(self in out nocopy ut_xunit_reporter) return self as result is
begin
self.init($$plsql_unit);
self.init($$plsql_unit,ut_output_bulk_buffer());
return;
end;

Expand Down
2 changes: 2 additions & 0 deletions source/uninstall_objects.sql
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ drop type ut_output_table_buffer force;

drop type ut_output_clob_table_buffer force;

drop type ut_output_bulk_buffer force;

drop type ut_output_buffer_base force;

drop table ut_output_buffer_tmp purge;
Expand Down
Loading