From 0f16efa584b90b359c729e4dba9ee00a3f32d128 Mon Sep 17 00:00:00 2001 From: Dmitry Volodin Date: Tue, 27 Jun 2017 21:07:14 +0300 Subject: [PATCH 1/2] dbms_lob_read_multibyte/Fix multibyte issue with dbms_lob.read --- source/core/ut_utils.pkb | 2 +- source/core/ut_utils.pks | 5 ++-- tests/RunAll.sql | 1 + .../ut_utils.clob_to_table_multibyte.sql | 23 +++++++++++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 tests/ut_utils/ut_utils.clob_to_table_multibyte.sql diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index 04ddcfadc..b1d1b6914 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -211,7 +211,7 @@ create or replace package body ut_utils is return l_result; end; - function clob_to_table(a_clob clob, a_max_amount integer := 32767, a_delimiter varchar2:= chr(10)) return ut_varchar2_list is + function clob_to_table(a_clob clob, a_max_amount integer := 24575, a_delimiter varchar2:= chr(10)) return ut_varchar2_list is l_offset integer := 1; l_length integer := dbms_lob.getlength(a_clob); l_amount integer; diff --git a/source/core/ut_utils.pks b/source/core/ut_utils.pks index 18d71a757..b794bb506 100644 --- a/source/core/ut_utils.pks +++ b/source/core/ut_utils.pks @@ -171,19 +171,20 @@ create or replace package ut_utils authid definer is Parameters: a_clob - the text to be split. a_delimiter - the delimiter character or string (default chr(10) ) - a_max_amount - the maximum length of returned string (default 32767) + a_max_amount - the maximum length of returned string (default 24575) Returns: ut_varchar2_list - table of string Splits a given string into table of string by delimiter. + Default value of a_max_amount is 24575 because of code can contains multibyte character. The delimiter gets removed. If null passed as any of the parameters, empty table is returned. If split text is longer than a_max_amount it gets split into pieces of a_max_amount. If no text between delimiters found then an empty row is returned, example: string_to_table( 'a,,b', ',' ) gives table ut_varchar2_list( 'a', null, 'b' ); */ - function clob_to_table(a_clob clob, a_max_amount integer := 32767, a_delimiter varchar2:= chr(10)) return ut_varchar2_list; + function clob_to_table(a_clob clob, a_max_amount integer := 24575, a_delimiter varchar2:= chr(10)) return ut_varchar2_list; function table_to_clob(a_text_table ut_varchar2_list, a_delimiter varchar2:= chr(10)) return clob; diff --git a/tests/RunAll.sql b/tests/RunAll.sql index 70a3480a6..a9ad83126 100644 --- a/tests/RunAll.sql +++ b/tests/RunAll.sql @@ -227,6 +227,7 @@ exec ut_coverage.coverage_start_develop(); @@lib/RunTest.sql ut_test_suite/ut_test_suite.Rollback_type.ManualOnFailure.sql @@ut_utils/ut_utils.clob_to_table.sql +@@ut_utils/ut_utils.clob_to_table_multibyte.sql @@ut_utils/ut_utils.table_to_clob.sql @@lib/RunTest.sql ut_utils/ut_utils.append_to_clob.worksWithMultiByteChars.sql @@lib/RunTest.sql ut_utils/ut_utils.test_result_to_char.RunsWithInvalidValues.sql diff --git a/tests/ut_utils/ut_utils.clob_to_table_multibyte.sql b/tests/ut_utils/ut_utils.clob_to_table_multibyte.sql new file mode 100644 index 000000000..5872b7e1b --- /dev/null +++ b/tests/ut_utils/ut_utils.clob_to_table_multibyte.sql @@ -0,0 +1,23 @@ +--Arrange +declare + l_varchar2_byte_limit integer := 32767; + l_workaround_byte_limit integer := 24575; + l_singlebyte_string_max_size varchar2(32767 char) := rpad('x',l_varchar2_byte_limit,'x'); + l_twobyte_character char(1 char) := 'ж'; + l_clob_multibyte clob := l_twobyte_character||l_singlebyte_string_max_size; --here we have 32769(2+32767) bytes and 32768 chars + l_expected ut_varchar2_list := ut_varchar2_list(); + l_result ut_varchar2_list; +begin + l_expected.extend(2); + l_expected(1) := l_twobyte_character||substr(l_singlebyte_string_max_size,1,l_workaround_byte_limit-1); + l_expected(2) := substr(l_singlebyte_string_max_size,l_workaround_byte_limit-1+1); +--Act + l_result := ut_utils.clob_to_table(l_clob_multibyte); +--Assert + if l_result = l_expected then + :test_result := ut_utils.tr_success; + else + dbms_output.put_line('expected: lengths '||length(l_expected(1))||' and '||length(l_expected(2))||', got lengths: '||length(l_result(1))||' and '||length(l_result(2))); + end if; +end; +/ \ No newline at end of file From e131e4be142bbbf20676a4e81b57596fdb449d19 Mon Sep 17 00:00:00 2001 From: Dmitry Volodin Date: Tue, 27 Jun 2017 23:25:17 +0300 Subject: [PATCH 2/2] Use 8191 instead of 24575 --- source/core/ut_utils.pkb | 4 ++-- source/core/ut_utils.pks | 6 +++--- tests/ut_utils/ut_utils.clob_to_table_multibyte.sql | 9 ++++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index b1d1b6914..a858e1b8a 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -211,7 +211,7 @@ create or replace package body ut_utils is return l_result; end; - function clob_to_table(a_clob clob, a_max_amount integer := 24575, a_delimiter varchar2:= chr(10)) return ut_varchar2_list is + function clob_to_table(a_clob clob, a_max_amount integer := 8191, a_delimiter varchar2:= chr(10)) return ut_varchar2_list is l_offset integer := 1; l_length integer := dbms_lob.getlength(a_clob); l_amount integer; @@ -329,4 +329,4 @@ create or replace package body ut_utils is end; end ut_utils; -/ +/ \ No newline at end of file diff --git a/source/core/ut_utils.pks b/source/core/ut_utils.pks index b794bb506..18ee4f9ce 100644 --- a/source/core/ut_utils.pks +++ b/source/core/ut_utils.pks @@ -171,20 +171,20 @@ create or replace package ut_utils authid definer is Parameters: a_clob - the text to be split. a_delimiter - the delimiter character or string (default chr(10) ) - a_max_amount - the maximum length of returned string (default 24575) + a_max_amount - the maximum length of returned string (default 8191) Returns: ut_varchar2_list - table of string Splits a given string into table of string by delimiter. - Default value of a_max_amount is 24575 because of code can contains multibyte character. + Default value of a_max_amount is 8191 because of code can contains multibyte character. The delimiter gets removed. If null passed as any of the parameters, empty table is returned. If split text is longer than a_max_amount it gets split into pieces of a_max_amount. If no text between delimiters found then an empty row is returned, example: string_to_table( 'a,,b', ',' ) gives table ut_varchar2_list( 'a', null, 'b' ); */ - function clob_to_table(a_clob clob, a_max_amount integer := 24575, a_delimiter varchar2:= chr(10)) return ut_varchar2_list; + function clob_to_table(a_clob clob, a_max_amount integer := 8191, a_delimiter varchar2:= chr(10)) return ut_varchar2_list; function table_to_clob(a_text_table ut_varchar2_list, a_delimiter varchar2:= chr(10)) return clob; diff --git a/tests/ut_utils/ut_utils.clob_to_table_multibyte.sql b/tests/ut_utils/ut_utils.clob_to_table_multibyte.sql index 5872b7e1b..692b3e7c0 100644 --- a/tests/ut_utils/ut_utils.clob_to_table_multibyte.sql +++ b/tests/ut_utils/ut_utils.clob_to_table_multibyte.sql @@ -1,23 +1,22 @@ --Arrange declare l_varchar2_byte_limit integer := 32767; - l_workaround_byte_limit integer := 24575; + l_workaround_byte_limit integer := 8191; l_singlebyte_string_max_size varchar2(32767 char) := rpad('x',l_varchar2_byte_limit,'x'); l_twobyte_character char(1 char) := 'ж'; l_clob_multibyte clob := l_twobyte_character||l_singlebyte_string_max_size; --here we have 32769(2+32767) bytes and 32768 chars l_expected ut_varchar2_list := ut_varchar2_list(); l_result ut_varchar2_list; begin - l_expected.extend(2); + l_expected.extend(1); l_expected(1) := l_twobyte_character||substr(l_singlebyte_string_max_size,1,l_workaround_byte_limit-1); - l_expected(2) := substr(l_singlebyte_string_max_size,l_workaround_byte_limit-1+1); --Act l_result := ut_utils.clob_to_table(l_clob_multibyte); --Assert - if l_result = l_expected then + if l_result(1) = l_expected(1) then :test_result := ut_utils.tr_success; else - dbms_output.put_line('expected: lengths '||length(l_expected(1))||' and '||length(l_expected(2))||', got lengths: '||length(l_result(1))||' and '||length(l_result(2))); + dbms_output.put_line('expected: 1st string length '||length(l_expected(1))||', got 1st string length: '||length(l_result(1))); end if; end; / \ No newline at end of file