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

Skip to content

Commit 9a8fb25

Browse files
authored
Merge pull request #105 from jgebal/feature/add_output_dbms_pipe
Feature/add output dbms pipe
2 parents 160c3a8 + 13e9c55 commit 9a8fb25

41 files changed

Lines changed: 1087 additions & 58 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.travis/create_utplsql_user.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ create user &ut3_user identified by &ut3_password default tablespace &ut3_tables
1313

1414
grant create session, create procedure, create type, create table to &ut3_user;
1515

16+
grant execute on dbms_pipe to &ut3_user;
17+
grant create job to &ut3_user;
18+
1619
grant alter session to &ut3_user;
1720

21+
--only needed to run unit tests for utplsql v3, not required to run utplsql v3 itself
22+
grant select any dictionary to &ut3_user;
23+
1824
exit success

examples/ut_custom_reporter.tpb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ create or replace type body ut_custom_reporter is
1616
return tab_str;
1717
end tab;
1818

19-
overriding member procedure print(a_text varchar2) is
19+
overriding member procedure print_text(a_text varchar2) is
2020
begin
21-
(self as ut_dbms_output_suite_reporter).print(tab || a_text);
22-
end print;
21+
(self as ut_dbms_output_suite_reporter).print_text(tab || a_text);
22+
end;
2323

2424
overriding member procedure before_suite(self in out nocopy ut_custom_reporter, a_suite ut_object) as
2525
begin

examples/ut_custom_reporter.tps

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ create or replace type ut_custom_reporter under ut_dbms_output_suite_reporter
66
-- Member functions and procedures
77
constructor function ut_custom_reporter(a_tab_size integer default 4, a_output ut_output default ut_output_dbms_output() ) return self as result,
88
member function tab(self in ut_custom_reporter) return varchar2,
9-
overriding member procedure print(a_text varchar2),
9+
overriding member procedure print_text(a_text varchar2),
1010
overriding member procedure before_suite(self in out nocopy ut_custom_reporter, a_suite ut_object),
1111
overriding member procedure before_test(self in out nocopy ut_custom_reporter, a_test ut_object),
1212
overriding member procedure on_assert_process(self in out nocopy ut_custom_reporter, a_assert ut_object),

source/core/types/ut_clob_list.tps

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
create or replace type ut_clob_list as table of clob
2+
/

source/core/types/ut_output.tps

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ create or replace type ut_output as object (
33
output_id varchar2(128),
44
final member function generate_output_id return varchar2,
55
not instantiable member procedure open(self in out nocopy ut_output),
6-
not instantiable member procedure send(self in out nocopy ut_output, a_text clob),
7-
not instantiable member procedure close(self in out nocopy ut_output)
6+
not instantiable member procedure send_line(self in out nocopy ut_output, a_text varchar2),
7+
not instantiable member procedure send_clob(self in out nocopy ut_output, a_text clob),
8+
not instantiable member procedure close(self in out nocopy ut_output),
9+
not instantiable member function get_lines(a_output_id varchar2) return ut_varchar2_list pipelined,
10+
not instantiable member function get_clob_lines(a_output_id varchar2) return ut_clob_list pipelined
811
) not final not instantiable
912
/

source/core/types/ut_output_dbms_output.tpb

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,17 @@ create or replace type body ut_output_dbms_output as
1212
null;
1313
end;
1414

15-
overriding member procedure send(self in out nocopy ut_output_dbms_output, a_text clob) is
16-
l_text_part varchar2(32767 byte);
17-
--we're assuming max of 2 bytes per char
18-
c_size_limit_chars constant integer := (32767/2);
19-
i integer := 0;
15+
overriding member procedure send_line(self in out nocopy ut_output_dbms_output, a_text varchar2) is
2016
begin
21-
while i < length(a_text) loop
22-
l_text_part := substr( a_text, i + 1, c_size_limit_chars );
23-
dbms_output.put_line(l_text_part);
24-
i := i + c_size_limit_chars;
17+
dbms_output.put_line(a_text);
18+
end;
19+
20+
overriding member procedure send_clob(self in out nocopy ut_output_dbms_output, a_text clob) is
21+
l_buffer ut_varchar2_list;
22+
begin
23+
l_buffer := ut_utils.clob_to_table(a_text);
24+
for i in 1 .. l_buffer.count loop
25+
dbms_output.put_line(l_buffer(i));
2526
end loop;
2627
end;
2728

@@ -30,5 +31,35 @@ create or replace type body ut_output_dbms_output as
3031
null;
3132
end;
3233

34+
overriding final member function get_lines(a_output_id varchar2) return ut_varchar2_list pipelined is
35+
l_buffer varchar2(32767);
36+
l_status integer;
37+
c_max_line_length constant integer := 4000;
38+
l_results_tab ut_varchar2_list;
39+
begin
40+
loop
41+
dbms_output.get_line (l_buffer, l_status);
42+
exit when l_status != 0;
43+
l_results_tab := ut_utils.clob_to_table(l_buffer, c_max_line_length);
44+
--pipe results one by one
45+
for i in 1 .. l_results_tab.count loop
46+
pipe row( l_results_tab(i) );
47+
end loop;
48+
end loop;
49+
return;
50+
end;
51+
52+
overriding final member function get_clob_lines(a_output_id varchar2) return ut_clob_list pipelined is
53+
l_buffer varchar2(32767);
54+
l_status integer;
55+
begin
56+
loop
57+
dbms_output.get_line (l_buffer, l_status);
58+
exit when l_status != 0;
59+
pipe row(l_buffer);
60+
end loop;
61+
return;
62+
end;
63+
3364
end;
3465
/
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
create or replace type ut_output_dbms_output under ut_output (
22
constructor function ut_output_dbms_output(self in out nocopy ut_output_dbms_output) return self as result,
33
overriding member procedure open(self in out nocopy ut_output_dbms_output),
4-
overriding member procedure send(self in out nocopy ut_output_dbms_output, a_text clob),
5-
overriding member procedure close(self in out nocopy ut_output_dbms_output)
4+
overriding member procedure send_line(self in out nocopy ut_output_dbms_output, a_text varchar2),
5+
overriding member procedure send_clob(self in out nocopy ut_output_dbms_output, a_text clob),
6+
overriding member procedure close(self in out nocopy ut_output_dbms_output),
7+
overriding final member function get_lines(a_output_id varchar2) return ut_varchar2_list pipelined,
8+
overriding final member function get_clob_lines(a_output_id varchar2) return ut_clob_list pipelined
69
) not final
710
/
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
create or replace type body ut_output_dbms_pipe as
2+
3+
constructor function ut_output_dbms_pipe(self in out nocopy ut_output_dbms_pipe) return self as result is
4+
begin
5+
self.output_type := $$plsql_unit;
6+
self.output_id := self.generate_output_id;
7+
return;
8+
end;
9+
10+
overriding member procedure open(self in out nocopy ut_output_dbms_pipe) is
11+
l_flag integer;
12+
begin
13+
--create an explicit private pipe. Explicitly created pipes need to be removed explicitly
14+
--otherwise they stay in memmory forever https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_pipe.htm#CHDEICJI
15+
--to check if there are any non-purged pipes execute: select * from v$db_pipes where pipe_size > 0 order by name desc;
16+
l_flag := dbms_pipe.create_pipe(self.output_id);
17+
end;
18+
19+
overriding member procedure send_line(self in out nocopy ut_output_dbms_pipe, a_text varchar2) is
20+
begin
21+
self.send_clob(a_text);
22+
end;
23+
24+
overriding member procedure send_clob(self in out nocopy ut_output_dbms_pipe, a_text clob) is
25+
c_size_limit_chars constant integer := ut_output_pipe_helper.gc_size_limit_chars;
26+
l_text_part ut_output_pipe_helper.t_pipe_item;
27+
i integer := 0;
28+
begin
29+
--split test into pieces of a size valid for pipe and send to pipe
30+
while i < length(a_text) loop
31+
l_text_part := substr( a_text, i + 1, c_size_limit_chars );
32+
ut_output_pipe_helper.send_text( self.output_id, l_text_part);
33+
i := i + c_size_limit_chars;
34+
end loop;
35+
--SEND is closed by a EOM message
36+
ut_output_pipe_helper.send_eom(self.output_id);
37+
end;
38+
39+
--we do not remove the pipe here, it is responsibility of the consumer,
40+
--when the pipe is fully consumed (recieved 'eot') then the consumer removed the pipe
41+
overriding member procedure close(self in out nocopy ut_output_dbms_pipe, a_timeout_sec integer) is
42+
begin
43+
ut_output_pipe_helper.send_eot(self.output_id);
44+
ut_output_pipe_helper.flush(self.output_id, a_timeout_sec);
45+
end;
46+
47+
overriding member function get_lines(a_output_id varchar2, a_timeout_sec naturaln) return ut_varchar2_list pipelined is
48+
c_max_line_length constant integer := 4000;
49+
l_text clob;
50+
l_result_flag integer;
51+
l_results_tab ut_varchar2_list;
52+
begin
53+
if a_output_id is null then
54+
return;
55+
end if;
56+
57+
loop
58+
dbms_lob.createtemporary(l_text, true);
59+
--get message as a clob data and recieve information if the message is ended, timed out or it is the end of transmission
60+
l_result_flag := ut_output_pipe_helper.get_message(a_output_id, a_timeout_sec, l_text);
61+
-- convert message into collection of varchar2(4000) for SQL processing
62+
l_results_tab := ut_utils.clob_to_table(l_text, c_max_line_length);
63+
--pipe results one by one
64+
for i in 1 .. l_results_tab.count loop
65+
pipe row( l_results_tab(i) );
66+
end loop;
67+
dbms_lob.freetemporary(l_text);
68+
69+
exit when l_result_flag in (ut_output_pipe_helper.gc_eot, ut_output_pipe_helper.gc_timeout);
70+
end loop;
71+
if l_result_flag = ut_output_pipe_helper.gc_eot then
72+
ut_output_pipe_helper.remove_pipe(a_output_id);
73+
end if;
74+
return;
75+
end;
76+
77+
overriding final member function get_clob_lines(a_output_id varchar2, a_timeout_sec naturaln) return ut_clob_list pipelined is
78+
l_text clob;
79+
l_result_flag integer;
80+
l_results_tab ut_varchar2_list;
81+
begin
82+
if a_output_id is null then
83+
return;
84+
end if;
85+
86+
loop
87+
dbms_lob.createtemporary(l_text, true);
88+
l_result_flag := ut_output_pipe_helper.get_message(a_output_id, a_timeout_sec, l_text);
89+
exit when l_result_flag in (ut_output_pipe_helper.gc_eot, ut_output_pipe_helper.gc_timeout);
90+
pipe row( l_text );
91+
dbms_lob.freetemporary(l_text);
92+
end loop;
93+
dbms_lob.freetemporary(l_text);
94+
if l_result_flag = ut_output_pipe_helper.gc_eot then
95+
ut_output_pipe_helper.remove_pipe(a_output_id);
96+
end if;
97+
return;
98+
end;
99+
100+
end;
101+
/
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
create or replace type ut_output_dbms_pipe under ut_output_stream (
2+
constructor function ut_output_dbms_pipe(self in out nocopy ut_output_dbms_pipe) return self as result,
3+
overriding member procedure open(self in out nocopy ut_output_dbms_pipe),
4+
overriding member procedure send_line(self in out nocopy ut_output_dbms_pipe, a_text varchar2),
5+
overriding member procedure send_clob(self in out nocopy ut_output_dbms_pipe, a_text clob),
6+
overriding member procedure close(self in out nocopy ut_output_dbms_pipe, a_timeout_sec integer),
7+
overriding member function get_lines(a_output_id varchar2, a_timeout_sec naturaln) return ut_varchar2_list pipelined,
8+
overriding final member function get_clob_lines(a_output_id varchar2, a_timeout_sec naturaln) return ut_clob_list pipelined
9+
) not final
10+
/
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
create or replace type body ut_output_stream as
2+
3+
overriding final member procedure close(self in out nocopy ut_output_stream) is
4+
begin
5+
self.close( a_timeout_sec=>60 );
6+
end;
7+
8+
overriding final member function get_lines(a_output_id varchar2) return ut_varchar2_list pipelined is
9+
begin
10+
for i in ( select column_value from table( self.get_lines(a_output_id, 60*60*4) ) ) loop
11+
pipe row(i.column_value);
12+
end loop;
13+
return;
14+
end;
15+
16+
overriding final member function get_clob_lines(a_output_id varchar2) return ut_clob_list pipelined is
17+
begin
18+
for i in ( select column_value from table( self.get_clob_lines(a_output_id, 60*60*4) ) ) loop
19+
pipe row(i.column_value);
20+
end loop;
21+
return;
22+
end;
23+
24+
end;
25+
/

0 commit comments

Comments
 (0)