11create or replace package body ut_output_pipe_helper is
22
33 -- private
4-
5- type tt_pipe_buffer is table of varchar2(4000);
4+ type t_pipe_buffer_rec is record(
5+ message_type integer,
6+ message varchar2(4000)
7+ );
8+ type tt_pipe_buffer is table of t_pipe_buffer_rec;
69
710 type t_output_buffer is record(
811 to_flush boolean := false,
@@ -26,7 +29,13 @@ create or replace package body ut_output_pipe_helper is
2629 --iterate through buffer and try to sent all data from buffer
2730 -- exit loop on timeout
2831 while i is not null loop
29- dbms_pipe.pack_message( a_buffer(i) );
32+ if a_buffer(i).message_type = gc_eom then
33+ dbms_pipe.pack_message_rowid( NULL );
34+ elsif a_buffer(i).message_type = gc_eot then
35+ dbms_pipe.pack_message_raw( NULL );
36+ else
37+ dbms_pipe.pack_message( a_buffer(i).message );
38+ end if;
3039 l_is_successful := dbms_pipe.send_message(a_output_id, a_timeout_seconds) = 0;
3140 exit when not l_is_successful;
3241 l_last_item := i;
@@ -57,6 +66,7 @@ create or replace package body ut_output_pipe_helper is
5766 --iterates through all the output buffers that were not purged
5867 --for each buffer tries to send the content of the buffer
5968 --if all content was sent, buffer is recycled (removed)
69+ --returns true if the flushing succeeded for all buffers
6070 function flush_buffers(a_timeout_seconds naturaln := 0) return boolean is
6171 l_output_id t_output_id;
6272 l_output_id_to_delete t_output_id;
@@ -66,10 +76,10 @@ create or replace package body ut_output_pipe_helper is
6676 l_output_id := g_outputs_buffer.first;
6777 while l_output_id is not null loop
6878 l_output_id_to_delete := null;
69- if send_from_buffer(l_output_id, a_timeout_seconds) = true then
79+
80+ l_timed_out := not send_from_buffer(l_output_id, a_timeout_seconds);
81+ if not l_timed_out then
7082 l_output_id_to_delete := l_output_id;
71- else
72- l_timed_out := true;
7383 end if;
7484 l_output_id := g_outputs_buffer.next(l_output_id);
7585
@@ -95,27 +105,33 @@ create or replace package body ut_output_pipe_helper is
95105 return true;
96106 end;
97107
98- --remove all the pipes anf purges all the buffers
108+ -- - remove pipes associated with buffers that are not yet deleted
109+ -- - delete all the buffers
110+ -- TODO - The purge procedure needs to be called by top level program (ut_runner)
111+ -- in the EXCEPTION WHEN OTHERS block before raising back,
112+ -- so that it tries to remove pipes on any exception before raising back to caller
99113 procedure purge is
100114 l_pipe_removal_status integer;
101115 l_output_id t_output_id;
102116 begin
103117 l_output_id := g_outputs_buffer.first;
104118 while l_output_id is not null loop
119+ l_pipe_removal_status := dbms_pipe.remove_pipe(l_output_id);
105120 l_output_id := g_outputs_buffer.next(l_output_id);
106121 end loop;
107122 g_outputs_buffer.delete;
108123 end;
109124
110125 --writes the message to the end of the buffer
111- procedure buffer(a_output_id t_output_id, a_text t_pipe_item) is
126+ procedure buffer(a_output_id t_output_id, a_text t_pipe_item, a_message_type integer := null ) is
112127 begin
113128 if not g_outputs_buffer.exists(a_output_id) then
114129 g_outputs_buffer(a_output_id).data := tt_pipe_buffer();
115130 g_outputs_buffer(a_output_id).to_flush := false;
116131 end if;
117132 g_outputs_buffer(a_output_id).data.extend;
118- g_outputs_buffer(a_output_id).data(g_outputs_buffer(a_output_id).data.last) := a_text;
133+ g_outputs_buffer(a_output_id).data(g_outputs_buffer(a_output_id).data.last).message_type := a_message_type;
134+ g_outputs_buffer(a_output_id).data(g_outputs_buffer(a_output_id).data.last).message := a_text;
119135 end;
120136
121137
@@ -131,10 +147,27 @@ create or replace package body ut_output_pipe_helper is
131147 l_is_successful := send_from_buffer(a_output_id);
132148 end;
133149
150+ --sends a end of message into a a pipe
151+ procedure send_eom(a_output_id t_output_id) is
152+ l_is_successful boolean;
153+ begin
154+ buffer(a_output_id, null, gc_eom);
155+ l_is_successful := send_from_buffer(a_output_id);
156+ end;
157+
158+ --sends a end of message into a a pipe
159+ procedure send_eot(a_output_id t_output_id) is
160+ l_is_successful boolean;
161+ begin
162+ buffer(a_output_id, null, gc_eot);
163+ l_is_successful := send_from_buffer(a_output_id);
164+ end;
165+
134166 --marks a buffer as ready to be flushed
135167 --tries to flush all the data from all the outputs buffers to the pipes immediately
136168 --in case, all buffers outputs are to be flused, it will try with a timeout.
137169 procedure flush(a_output_id t_output_id, a_timeout_seconds naturaln := gc_flush_timeout_seconds) is
170+ l_buffers_flushed boolean := false;
138171 begin
139172 if g_outputs_buffer.exists(a_output_id) then
140173 g_outputs_buffer(a_output_id).to_flush := true;
@@ -144,9 +177,16 @@ create or replace package body ut_output_pipe_helper is
144177 --try as many times as there are seconds for timeout
145178 --each time try with one second delay
146179 for i in 1 .. a_timeout_seconds loop
147- exit when flush_buffers(a_timeout_seconds => 1) = true;
180+ l_buffers_flushed := flush_buffers(a_timeout_seconds => 1);
181+ exit when l_buffers_flushed;
148182 end loop;
149- purge();
183+
184+ --if timeout occured and buffers were not flushed then
185+ -- - remove pipes associated with non flushed buffers
186+ -- - delete the buffers
187+ if not l_buffers_flushed then
188+ purge();
189+ end if;
150190 end if;
151191
152192 end;
0 commit comments