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

Skip to content

Commit 3648ee4

Browse files
committed
Fixed bug, where after a split by line size, a leading delimiter caused empty line to apperar.
Fixed bug in unit tests. Worked around a bug wiht Oracle not handling consecutive assignments to collection in pipelined function (used pipelined function)
1 parent 6968243 commit 3648ee4

6 files changed

Lines changed: 79 additions & 42 deletions

File tree

source/core/ut_utils.pkb

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -126,27 +126,33 @@ create or replace package body ut_utils is
126126
return case a_value when 1 then true when 0 then false end;
127127
end;
128128

129-
function string_to_table(a_string varchar2, a_delimiter varchar2:= chr(10)) return ut_output_varchar2_list is
129+
function string_to_table(a_string varchar2, a_delimiter varchar2:= chr(10), a_skip_leading_delimiter varchar2 := 'N') return ut_output_varchar2_list pipelined is
130130
l_offset integer := 1;
131131
l_length integer;
132-
l_result ut_output_varchar2_list := ut_output_varchar2_list();
133132
l_delimiter_position integer;
133+
l_skip_leading_delimiter boolean := coalesce(a_skip_leading_delimiter = 'Y',false);
134134
begin
135-
if a_string is not null and a_delimiter is not null then
136-
l_length := length(a_string);
137-
loop
138-
l_result.extend;
139-
l_delimiter_position := instr(a_string, a_delimiter, l_offset);
135+
if a_string is null then
136+
return;
137+
end if;
138+
if a_delimiter is null then
139+
pipe row(a_string);
140+
return;
141+
end if;
142+
l_length := length(a_string);
143+
loop
144+
l_delimiter_position := instr(a_string, a_delimiter, l_offset);
145+
if not (l_delimiter_position = 1 and l_skip_leading_delimiter) then
140146
if l_delimiter_position > 0 then
141-
l_result(l_result.last) := substr(a_string, l_offset, l_delimiter_position - l_offset);
147+
pipe row( substr(a_string, l_offset, l_delimiter_position - l_offset) );
142148
else
143-
l_result(l_result.last) := substr(a_string, l_offset);
149+
pipe row( substr(a_string, l_offset) );
144150
end if;
145-
exit when l_delimiter_position = 0;
146-
l_offset := l_delimiter_position + 1;
147-
end loop;
148-
end if;
149-
return l_result;
151+
end if;
152+
exit when l_delimiter_position = 0;
153+
l_offset := l_delimiter_position + 1;
154+
end loop;
155+
return;
150156
end;
151157

152158
function clob_to_table(a_clob clob, a_delimiter varchar2:= chr(10), a_max_amount integer := 32767) return ut_output_varchar2_list pipelined is
@@ -155,26 +161,37 @@ create or replace package body ut_utils is
155161
l_amount integer := a_max_amount;
156162
l_buffer varchar2(32767);
157163
l_last_line varchar2(32767);
158-
l_results ut_output_varchar2_list;
159-
l_is_last_line boolean;
164+
l_results ut_output_varchar2_list;
165+
l_has_last_line boolean;
166+
l_skip_leading_delimiter varchar2(1) := 'N';
160167
begin
161168
while l_offset <= l_length loop
162169
l_amount := a_max_amount - coalesce( length(l_last_line), 0 );
163170
dbms_lob.read(a_clob, l_amount, l_offset, l_buffer);
164171
l_offset := l_offset + l_amount;
165172

166-
l_results := string_to_table( l_last_line || l_buffer, a_delimiter );
167-
l_is_last_line := false;
173+
select column_value
174+
bulk collect into l_results
175+
from table( string_to_table( l_last_line || l_buffer, a_delimiter, l_skip_leading_delimiter ) );
168176
for i in 1 .. l_results.count loop
169-
if i < l_results.count or l_results.count = 1 then
177+
--if a split of lines was not done or not at the last line
178+
if l_results.count = 1 or i < l_results.count then
170179
pipe row( l_results(i) );
171-
else
172-
l_is_last_line := true;
173-
l_last_line := l_results(i);
174180
end if;
175181
end loop;
182+
183+
--check if we need to append the last line to the next element
184+
if l_results.count = 1 then
185+
l_has_last_line := false;
186+
l_last_line := null;
187+
elsif l_results.count > 1 then
188+
l_has_last_line := true;
189+
l_last_line := l_results(l_results.count);
190+
end if;
191+
192+
l_skip_leading_delimiter := 'Y';
176193
end loop;
177-
if l_is_last_line then
194+
if l_has_last_line then
178195
pipe row( l_last_line );
179196
end if;
180197
return;

source/core/ut_utils.pks

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ create or replace package ut_utils authid definer is
9595
Parameters:
9696
a_string - the text to be split.
9797
a_delimiter - the delimiter character or string
98+
a_skip_leading_delimiter - determines if the leading delimiter should be ignored, used by clob_to_table
9899

99100
Returns:
100101
ut_output_varchar2_list - table of string
@@ -106,7 +107,7 @@ create or replace package ut_utils authid definer is
106107
If no text between delimiters found then an empty row is returned, example:
107108
string_to_table( 'a,,b', ',' ) gives table ut_output_varchar2_list( 'a', null, 'b' );
108109
*/
109-
function string_to_table(a_string varchar2, a_delimiter varchar2:= chr(10)) return ut_output_varchar2_list;
110+
function string_to_table(a_string varchar2, a_delimiter varchar2:= chr(10), a_skip_leading_delimiter varchar2 := 'N') return ut_output_varchar2_list pipelined;
110111

111112
/*
112113
Function: clob_to_table

tests/RunAll.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ create table ut$test_table (val varchar2(1));
137137
@@lib/RunTest.sql ut_test_suite/ut_test_suite.Rollback_type.AutoOnFailure.sql
138138
@@lib/RunTest.sql ut_test_suite/ut_test_suite.Rollback_type.Manual.sql
139139
@@lib/RunTest.sql ut_test_suite/ut_test_suite.Rollback_type.ManualOnFailure.sql
140-
@@lib/RunTest.sql ut_utils/ut_utils.clob_to_table.sql
140+
@@ut_utils/ut_utils.clob_to_table.sql
141141
@@lib/RunTest.sql ut_utils/ut_utils.test_result_to_char.RunsWithInvalidValues.sql
142142
@@lib/RunTest.sql ut_utils/ut_utils.test_result_to_char.RunsWithNullValue.sql
143143
@@lib/RunTest.sql ut_utils/ut_utils.test_result_to_char.Success.sql

tests/lib/RunTest.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
var test_result number
22
exec :test_result := null;
33

4-
prompt
54
prompt Executing test: &1
65
--exec dbms_output.put_line(lpad('-',60,'-'));
76
exec :test_start_time := dbms_utility.get_time;
@@ -26,3 +25,5 @@ begin
2625
ut_assert_processor.clear_asserts;
2726
end;
2827
/
28+
29+
prompt

tests/ut_utils/common/ut_utils.clob_to_table.sql

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,38 @@ declare
66
l_result ut_output_varchar2_list;
77
l_limit integer := &4;
88
l_result_str varchar2(32767);
9+
l_errors integer := 0;
10+
function compare_element(a_element_id integer, a_expected ut_output_varchar2_list, a_actual ut_output_varchar2_list) return integer is
11+
begin
12+
if a_expected.exists(a_element_id) and a_actual.exists(a_element_id) then
13+
if a_expected(a_element_id) = a_actual(a_element_id) or a_expected(a_element_id) is null and a_actual(a_element_id) is null then
14+
return 0;
15+
else
16+
dbms_output.put('a_expected('||a_element_id||')='||a_expected(a_element_id)||' | a_actual('||a_element_id||')='||a_actual(a_element_id));
17+
end if;
18+
end if;
19+
if not a_expected.exists(a_element_id) then
20+
dbms_output.put('a_expected('||a_element_id||') does not exist ');
21+
end if;
22+
if not a_actual.exists(a_element_id) then
23+
dbms_output.put('a_actual('||a_element_id||') does not exist ');
24+
end if;
25+
dbms_output.put_line(null);
26+
return 1;
27+
end;
928
begin
1029
--Act
11-
select column_value
12-
bulk collect into l_result
13-
from table(ut_utils.clob_to_table(l_clob, l_delimiter, l_limit));
30+
select column_value bulk collect into l_result from table( ut_utils.clob_to_table(l_clob, l_delimiter, l_limit) );
1431
for i in 1 .. l_result.count loop
15-
if i = l_result.count then
16-
l_delimiter := null;
17-
end if;
18-
l_result_str := ''''||l_result(i)||l_delimiter||'''';
32+
l_result_str := l_result_str||''''||l_result(i)||''''||l_delimiter;
1933
end loop;
34+
l_result_str := rtrim(l_result_str,l_delimiter);
2035
--Assert
21-
if l_result = l_expected then
36+
for i in 1 .. greatest(l_expected.count, l_result.count) loop
37+
l_errors := l_errors + compare_element(i, l_expected, l_result);
38+
end loop;
39+
if l_errors = 0 then
2240
:test_result := ut_utils.tr_success;
23-
else
24-
dbms_output.put_line('expected: '||q'[&3]'||', got: ut_output_varchar2_list('||l_result_str||')' );
2541
end if;
2642
end;
2743
/
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
PROMPT Splits a given string into table of string by delimiter
2-
@@ut_utils/common/ut_utils.clob_to_table.sql 'a,b,c,d' ',' ut_output_varchar2_list('a','b','c','d') 1000
2+
@@lib/RunTest.sql "ut_utils/common/ut_utils.clob_to_table.sql 'a,b,c,d' ',' ut_output_varchar2_list('a','b','c','d') 1000"
33

4-
PROMPT If null passed as any of the parameters, empty table is returned.
5-
@@ut_utils/common/ut_utils.clob_to_table.sql '' ',' ut_output_varchar2_list() 1000
6-
@@ut_utils/common/ut_utils.clob_to_table.sql '1,b,c,d' '' ut_output_varchar2_list() 1000
4+
PROMPT If a_text is null then empty table is returned.
5+
@@lib/RunTest.sql "ut_utils/common/ut_utils.clob_to_table.sql '' ',' ut_output_varchar2_list() 1000"
6+
7+
PROMPT If a_delimiter is null then data is split by max size.
8+
@@lib/RunTest.sql "ut_utils/common/ut_utils.clob_to_table.sql '1,b,c,d' '' ut_output_varchar2_list('1,b,','c,d') 4"
79

810
PROMPT If split text is longer than a_max_amount it gets split into pieces of a_max_amount
9-
@@ut_utils/common/ut_utils.clob_to_table.sql 'abcdefg,hijk,axa,a' ',' ut_output_varchar2_list('abc','def','g','hij','k','axa','a') 3
11+
@@lib/RunTest.sql "ut_utils/common/ut_utils.clob_to_table.sql 'abcdefg,hijk,axa,a' ',' ut_output_varchar2_list('abc','def','g','hij','k','axa','a') 3"
1012

1113
PROMPT If no text between delimiters found then an empty row is returned
12-
@@ut_utils/common/ut_utils.clob_to_table.sql ',a,,c,d,' ',' ut_output_varchar2_list('','a','','c','d','') 1000
14+
@@lib/RunTest.sql "ut_utils/common/ut_utils.clob_to_table.sql ',a,,c,d,' ',' ut_output_varchar2_list('','a','','c','d','') 1000"
1315

1416

0 commit comments

Comments
 (0)