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

Skip to content

Commit 217913e

Browse files
committed
work in progress
1 parent 87d628c commit 217913e

7 files changed

Lines changed: 218 additions & 0 deletions

File tree

.travis/create_utplsql_user.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ 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

1821
exit success
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
create or replace type ut_output_clob_list as table of clob
2+
/
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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 := ut_output_dbms_pipe.generate_output_id;
7+
return;
8+
end;
9+
10+
overriding member procedure open(self in out nocopy ut_output_dbms_pipe) is
11+
l_buffer_size_bytes integer := 100 * 1024 * 1024;
12+
l_flag integer;
13+
begin
14+
--create an explixit private pipe
15+
--explicitly created pipes need to be removed explicitly
16+
--otherwise they stay in memmory forever
17+
--https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_pipe.htm#CHDEICJI
18+
--to check ig there are any non-purged pipes execute:
19+
--select * from v$db_pipes where pipe_size > 0 order by name desc;
20+
l_flag := dbms_pipe.create_pipe(self.output_id, l_buffer_size_bytes);
21+
end;
22+
23+
overriding member procedure send(self in out nocopy ut_output_dbms_pipe, a_text clob) is
24+
--we're assuming bax of 4 bytes per char
25+
c_size_limit_chars constant integer := 1000;
26+
l_text_part varchar2(4000 byte);
27+
l_timeout_occured boolean;
28+
i integer := 0;
29+
begin
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( self.output_id, l_text_part);
33+
i := i + c_size_limit_chars;
34+
end loop;
35+
ut_output_pipe_helper.send( self.output_id, ut_utils.gc_output_eom );
36+
end;
37+
38+
overriding member procedure close(self in out nocopy ut_output_dbms_pipe) is
39+
begin
40+
self.send(ut_utils.gc_output_eot);
41+
end;
42+
43+
static function get_lines(a_output_id varchar2, a_timeout_sec integer := 60*60*4) return ut_output_clob_list pipelined is
44+
l_flag integer;
45+
l_text_part varchar2(4000 byte);
46+
l_text clob;
47+
l_timeout_occured boolean;
48+
begin
49+
if a_output_id is null then
50+
return;
51+
end if;
52+
loop
53+
dbms_lob.createtemporary(l_text, true);
54+
loop
55+
l_timeout_occured := dbms_pipe.receive_message(a_output_id, a_timeout_sec) != 0;
56+
exit when l_timeout_occured;
57+
58+
dbms_pipe.unpack_message(l_text_part);
59+
exit when (l_text_part = ut_utils.gc_output_eom or l_text_part = ut_utils.gc_output_eot);
60+
dbms_lob.writeappend(l_text,length(l_text_part),l_text_part);
61+
end loop;
62+
pipe row( l_text );
63+
exit when (l_text_part = ut_utils.gc_output_eot);
64+
end loop;
65+
l_flag := dbms_pipe.remove_pipe(a_output_id);
66+
return;
67+
end;
68+
69+
member procedure to_screen(self in ut_output_dbms_pipe) is
70+
begin
71+
for i in (select column_value as text_line from table( ut_output_dbms_pipe.get_lines( self.output_id ) ) ) loop
72+
dbms_output.put_line(i.text_line);
73+
end loop;
74+
end;
75+
76+
static procedure to_screen(a_output_id varchar2) is
77+
begin
78+
for i in (select column_value as text_line from table( ut_output_dbms_pipe.get_lines( a_output_id ) ) ) loop
79+
dbms_output.put_line(i.text_line);
80+
end loop;
81+
end;
82+
end;
83+
/
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
create or replace type ut_output_dbms_pipe under ut_output (
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(self in out nocopy ut_output_dbms_pipe, a_text clob),
5+
overriding member procedure close(self in out nocopy ut_output_dbms_pipe),
6+
static function generate_output_id return varchar2,
7+
static function get_lines(a_output_id varchar2, a_timeout_sec integer := 60*60*4) return ut_output_clob_list pipelined,
8+
member procedure to_screen(self in ut_output_dbms_pipe),
9+
static procedure to_screen(a_output_id varchar2)
10+
) not final
11+
/
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
create or replace package body ut_output_pipe_helper is
2+
3+
4+
type t_pipe_buffer is table of varchar2(4000);
5+
type t_outputs_buffer is table of t_pipe_buffer index by varchar2(128);
6+
7+
g_outputs_buffer t_outputs_buffer;
8+
9+
procedure send_from_buffer(a_output_id varchar2) is
10+
l_timeout_occured boolean;
11+
i integer;
12+
begin
13+
if g_outputs_buffer.exists(a_output_id) then
14+
i := g_outputs_buffer(a_output_id).first;
15+
while i is not null loop
16+
dbms_pipe.pack_message( g_outputs_buffer(a_output_id)(i) );
17+
l_timeout_occured := dbms_pipe.send_message(a_output_id, 0) != 0;
18+
if l_timeout_occured then
19+
dbms_pipe.reset_buffer;
20+
return;
21+
end if;
22+
end loop;
23+
end if;
24+
end;
25+
26+
--sends a message to a named pipe
27+
--and if sending fails it writes the message to the end of the buffer for pipe
28+
procedure send(a_output_id varchar2, a_text varchar2) is
29+
l_timeout_occured boolean;
30+
begin
31+
send_from_buffer(a_output_id);
32+
dbms_pipe.pack_message( a_text );
33+
l_timeout_occured := dbms_pipe.send_message(a_output_id, 0) != 0;
34+
if l_timeout_occured then
35+
dbms_pipe.reset_buffer;
36+
buffer(a_output_id, a_text);
37+
end if;
38+
end;
39+
40+
--writes the message to the end of the buffer for pipe
41+
procedure buffer(a_output_id varchar2, a_text varchar2) is
42+
begin
43+
if not g_outputs_buffer.exists(a_output_id) then
44+
g_outputs_buffer(a_output_id) := t_pipe_buffer();
45+
end if;
46+
g_outputs_buffer(a_output_id).extend;
47+
g_outputs_buffer(a_output_id)(g_outputs_buffer(a_output_id).last) := a_text;
48+
end;
49+
50+
--registers a close request and tries to close a pipe
51+
--by first sending out all messages remaining in the buffers
52+
--the procedure holds infomrmation about closure requests
53+
--so that if close is not possble as buffer was not yet flusehd
54+
--it will proceed to other close requests
55+
--scenario with failure:
56+
-- two buffers used: output_1, output_2
57+
-- call is made to close output_1
58+
-- register the close request
59+
-- send all messaged from output_1 buffer
60+
-- if buffer not empty and timeout
61+
-- go to output_2
62+
-- if output_2 is still open, return
63+
-- so the outout_1 close request is in a pending state
64+
-- next a call should be made from framework to close output_2
65+
-- register the close request
66+
-- send all messaged from output_2 buffer
67+
-- if buffer not empty and timeout
68+
-- go to output_1
69+
-- if output_1 has a pending close
70+
-- try to send from output_1 buffer
71+
-- if timeout -> raise
72+
--scenario with success:
73+
-- two buffers used: output_1, output_2
74+
procedure request_close(a_output_id varchar2, a_text varchar2) is
75+
begin
76+
null;
77+
end;
78+
79+
end;
80+
/
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
create or replace package ut_output_pipe_helper is
2+
3+
--sends a message to a named pipe
4+
--and if sending fails it writes the message to the end of the buffer for pipe
5+
procedure send(a_output_id varchar2, a_text varchar2);
6+
7+
--writes the message to the end of the buffer for pipe
8+
procedure buffer(a_output_id varchar2, a_text varchar2);
9+
10+
--registers a close request and tries to close a pipe
11+
--by first sending out all messages remaining in the buffers
12+
--the procedure holds infomrmation about closure requests
13+
--so that if close is not possble as buffer was not yet flusehd
14+
--it will proceed to other close requests
15+
--scenario with failure:
16+
-- two buffers used: output_1, output_2
17+
-- call is made to close output_1
18+
-- register the close request
19+
-- send all messaged from output_1 buffer
20+
-- if buffer not empty and timeout
21+
-- go to output_2
22+
-- if output_2 is still open, return
23+
-- so the outout_1 close request is in a pending state
24+
-- next a call should be made from framework to close output_2
25+
-- register the close request
26+
-- send all messaged from output_2 buffer
27+
-- if buffer not empty and timeout
28+
-- go to output_1
29+
-- if output_1 has a pending close
30+
-- try to send from output_1 buffer
31+
-- if timeout -> raise
32+
--scenario with success:
33+
-- two buffers used: output_1, output_2
34+
procedure request_close(a_output_id varchar2, a_text varchar2);
35+
36+
end;
37+
/

source/core/ut_utils.pks

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ create or replace package ut_utils authid definer is
4040
gc_timestamp_format constant varchar2(100) := 'yyyy-mm-dd"T"hh24:mi:ssxff';
4141
gc_timestamp_tz_format constant varchar2(100) := 'yyyy-mm-dd"T"hh24:mi:ssxff tzh:tzm';
4242
gc_null_string constant varchar2(4) := 'NULL';
43+
gc_output_eom constant varchar2(30) := '[{-end-of-message-}]';
44+
gc_output_eot constant varchar2(30) := '[{-end-of-transmission-}]';
4345
/*
4446
Function: test_result_to_char
4547
returns a string representation of a test_result.

0 commit comments

Comments
 (0)