From 8b45b0d670d7212f4e1ffbc9635a4a1b2a621cf1 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 28 May 2023 16:00:15 +0300 Subject: [PATCH 1/2] Fix output length error and output buffer. When dealing with multibyte strings, the substring limit of 4000 **chars** is not correct. We need to apply a limit of 4000 **bytes** to both VARCHAR2 and to CLOB data types. This means we need to have a function to calculate lenght of CLOB in bytes. This is now added and all the conversions/trimming/string-splitting is done using the string length in **bytes** Additionally, a different approach (with sequences) was introduced into output buffers to avoid the sometime occurring PK violation on the output buffer tables. The new approach may add a but overhead on reading from / saving into buffer, but will definitely address the threat of PK errors. Resolves #1254 Resolves #1128 Replaced all regexp ranges with posix representations to avoid NLS_SORT impact on regex behavior. --- .../output_buffers/ut_output_buffer_base.tpb | 1 - .../output_buffers/ut_output_buffer_base.tps | 1 - .../output_buffers/ut_output_buffer_tmp.sql | 1 + .../output_buffers/ut_output_bulk_buffer.tpb | 9 ++-- .../ut_output_clob_buffer_tmp.sql | 2 + .../ut_output_clob_table_buffer.tpb | 17 ++----- .../output_buffers/ut_output_table_buffer.tpb | 27 ++++------ source/core/ut_utils.pkb | 48 ++++++++++++++--- source/core/ut_utils.pks | 5 ++ source/uninstall_objects.sql | 4 ++ test/ut3_tester/core/test_output_buffer.pkb | 51 ++++++++++++++++--- test/ut3_tester/core/test_output_buffer.pks | 6 +++ test/ut3_tester/core/test_ut_utils.pkb | 18 +++++++ test/ut3_tester/core/test_ut_utils.pks | 13 +++-- 14 files changed, 149 insertions(+), 54 deletions(-) diff --git a/source/core/output_buffers/ut_output_buffer_base.tpb b/source/core/output_buffers/ut_output_buffer_base.tpb index be4c92bd8..20cec335e 100644 --- a/source/core/output_buffers/ut_output_buffer_base.tpb +++ b/source/core/output_buffers/ut_output_buffer_base.tpb @@ -24,7 +24,6 @@ create or replace type body ut_output_buffer_base is self.self_type := coalesce(a_self_type,self.self_type); self.output_id := coalesce(a_output_id, self.output_id, sys_guid()); self.start_date := coalesce(self.start_date, sysdate); - self.last_write_message_id := 0; select /*+ no_parallel */ count(*) into l_exists from ut_output_buffer_info_tmp where output_id = self.output_id; if ( l_exists > 0 ) then update /*+ no_parallel */ ut_output_buffer_info_tmp set start_date = self.start_date where output_id = self.output_id; diff --git a/source/core/output_buffers/ut_output_buffer_base.tps b/source/core/output_buffers/ut_output_buffer_base.tps index 53be365ae..f2d9ec686 100644 --- a/source/core/output_buffers/ut_output_buffer_base.tps +++ b/source/core/output_buffers/ut_output_buffer_base.tps @@ -19,7 +19,6 @@ create or replace type ut_output_buffer_base force authid definer as object( output_id raw(32), is_closed number(1,0), start_date date, - last_write_message_id number(38,0), lock_handle varchar2(30 byte), self_type varchar2(250 byte), member procedure init(self in out nocopy ut_output_buffer_base, a_output_id raw := null, a_self_type varchar2 := null), diff --git a/source/core/output_buffers/ut_output_buffer_tmp.sql b/source/core/output_buffers/ut_output_buffer_tmp.sql index 57027817e..1ab19e534 100644 --- a/source/core/output_buffers/ut_output_buffer_tmp.sql +++ b/source/core/output_buffers/ut_output_buffer_tmp.sql @@ -30,3 +30,4 @@ create table ut_output_buffer_tmp( ) organization index nologging initrans 100 overflow nologging initrans 100; +create sequence ut_output_buffer_tmp_seq cache 20; diff --git a/source/core/output_buffers/ut_output_bulk_buffer.tpb b/source/core/output_buffers/ut_output_bulk_buffer.tpb index ceae07862..cfc173e95 100644 --- a/source/core/output_buffers/ut_output_bulk_buffer.tpb +++ b/source/core/output_buffers/ut_output_bulk_buffer.tpb @@ -34,9 +34,8 @@ create or replace type body ut_output_bulk_buffer is a_item_type ); else - self.last_write_message_id := self.last_write_message_id + 1; insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) - values (self.output_id, self.last_write_message_id, a_text, a_item_type); + values (self.output_id, ut_output_buffer_tmp_seq.nextval, a_text, a_item_type); end if; commit; end if; @@ -46,10 +45,9 @@ create or replace type body ut_output_bulk_buffer is pragma autonomous_transaction; begin insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) - select /*+ no_parallel */ self.output_id, self.last_write_message_id + rownum, t.column_value, a_item_type + select /*+ no_parallel */ self.output_id, ut_output_buffer_tmp_seq.nextval, t.column_value, a_item_type from table(a_text_list) t where t.column_value is not null or a_item_type is not null; - self.last_write_message_id := self.last_write_message_id + sql%rowcount; commit; end; @@ -65,9 +63,8 @@ create or replace type body ut_output_bulk_buffer is a_item_type ); else - self.last_write_message_id := self.last_write_message_id + 1; insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) - values (self.output_id, self.last_write_message_id, a_text, a_item_type); + values (self.output_id, ut_output_buffer_tmp_seq.nextval, a_text, a_item_type); end if; commit; end if; diff --git a/source/core/output_buffers/ut_output_clob_buffer_tmp.sql b/source/core/output_buffers/ut_output_clob_buffer_tmp.sql index 40dda121f..9ff9f7413 100644 --- a/source/core/output_buffers/ut_output_clob_buffer_tmp.sql +++ b/source/core/output_buffers/ut_output_clob_buffer_tmp.sql @@ -45,3 +45,5 @@ begin end; end; / + +create sequence ut_output_clob_buffer_tmp_seq cache 20; diff --git a/source/core/output_buffers/ut_output_clob_table_buffer.tpb b/source/core/output_buffers/ut_output_clob_table_buffer.tpb index c4cfdb059..3d49ab08d 100644 --- a/source/core/output_buffers/ut_output_clob_table_buffer.tpb +++ b/source/core/output_buffers/ut_output_clob_table_buffer.tpb @@ -26,9 +26,8 @@ create or replace type body ut_output_clob_table_buffer is pragma autonomous_transaction; begin if a_text is not null or a_item_type is not null then - self.last_write_message_id := self.last_write_message_id + 1; insert /*+ no_parallel */ into ut_output_clob_buffer_tmp(output_id, message_id, text, item_type) - values (self.output_id, self.last_write_message_id, a_text, a_item_type); + values (self.output_id, ut_output_clob_buffer_tmp_seq.nextval, a_text, a_item_type); end if; commit; end; @@ -37,10 +36,9 @@ create or replace type body ut_output_clob_table_buffer is pragma autonomous_transaction; begin insert /*+ no_parallel */ into ut_output_clob_buffer_tmp(output_id, message_id, text, item_type) - select /*+ no_parallel */ self.output_id, self.last_write_message_id + rownum, t.column_value, a_item_type + select /*+ no_parallel */ self.output_id, ut_output_clob_buffer_tmp_seq.nextval, t.column_value, a_item_type from table(a_text_list) t where t.column_value is not null or a_item_type is not null; - self.last_write_message_id := self.last_write_message_id + SQL%rowcount; commit; end; @@ -48,9 +46,8 @@ create or replace type body ut_output_clob_table_buffer is pragma autonomous_transaction; begin if a_text is not null and a_text != empty_clob() or a_item_type is not null then - self.last_write_message_id := self.last_write_message_id + 1; insert /*+ no_parallel */ into ut_output_clob_buffer_tmp(output_id, message_id, text, item_type) - values (self.output_id, self.last_write_message_id, a_text, a_item_type); + values (self.output_id, ut_output_clob_buffer_tmp_seq.nextval, a_text, a_item_type); end if; commit; end; @@ -60,7 +57,6 @@ create or replace type body ut_output_clob_table_buffer is l_buffer_rowids ut_varchar2_rows; l_buffer_data ut_output_data_rows; l_finished_flags ut_integer_list; - l_last_read_message_id integer; l_already_waited_sec number(10,2) := 0; l_finished boolean := false; l_sleep_time number(2,1); @@ -68,25 +64,22 @@ create or replace type body ut_output_clob_table_buffer is l_producer_started boolean := false; l_producer_finished boolean := false; procedure get_data_from_buffer_table( - a_last_read_message_id in out nocopy integer, a_buffer_data out nocopy ut_output_data_rows, a_buffer_rowids out nocopy ut_varchar2_rows, a_finished_flags out nocopy ut_integer_list ) is lc_bulk_limit constant integer := 5000; begin - a_last_read_message_id := coalesce(a_last_read_message_id, 0); with ordered_buffer as ( select /*+ no_parallel index(a) */ ut_output_data_row(a.text, a.item_type), rowidtochar(a.rowid), is_finished from ut_output_clob_buffer_tmp a where a.output_id = self.output_id - and a.message_id <= a_last_read_message_id + lc_bulk_limit + and a.message_id <= (select min(message_id) from ut_output_clob_buffer_tmp o where o.output_id = self.output_id) + lc_bulk_limit order by a.message_id ) select /*+ no_parallel */ b.* bulk collect into a_buffer_data, a_buffer_rowids, a_finished_flags from ordered_buffer b; - a_last_read_message_id := a_last_read_message_id + a_finished_flags.count; end; procedure remove_read_data(a_buffer_rowids ut_varchar2_rows) is @@ -103,7 +96,7 @@ create or replace type body ut_output_clob_table_buffer is l_sleep_time := case when l_already_waited_sec >= 1 then 0.5 else 0.1 end; l_lock_status := self.get_lock_status(); - get_data_from_buffer_table( l_last_read_message_id, l_buffer_data, l_buffer_rowids, l_finished_flags ); + get_data_from_buffer_table( l_buffer_data, l_buffer_rowids, l_finished_flags ); if l_buffer_data.count > 0 then l_already_waited_sec := 0; diff --git a/source/core/output_buffers/ut_output_table_buffer.tpb b/source/core/output_buffers/ut_output_table_buffer.tpb index 480ae9144..e8e2442a7 100644 --- a/source/core/output_buffers/ut_output_table_buffer.tpb +++ b/source/core/output_buffers/ut_output_table_buffer.tpb @@ -26,7 +26,7 @@ create or replace type body ut_output_table_buffer is pragma autonomous_transaction; begin if a_text is not null or a_item_type is not null then - if length(a_text) > ut_utils.gc_max_storage_varchar2_len then + if lengthb(a_text) > ut_utils.gc_max_storage_varchar2_len then self.send_lines( ut_utils.convert_collection( ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len) @@ -34,9 +34,8 @@ create or replace type body ut_output_table_buffer is a_item_type ); else - self.last_write_message_id := self.last_write_message_id + 1; insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) - values (self.output_id, self.last_write_message_id, a_text, a_item_type); + values (self.output_id, ut_output_buffer_tmp_seq.nextval, a_text, a_item_type); end if; commit; end if; @@ -46,10 +45,9 @@ create or replace type body ut_output_table_buffer is pragma autonomous_transaction; begin insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) - select /*+ no_parallel */ self.output_id, self.last_write_message_id + rownum, t.column_value, a_item_type + select /*+ no_parallel */ self.output_id, ut_output_buffer_tmp_seq.nextval, t.column_value, a_item_type from table(a_text_list) t where t.column_value is not null or a_item_type is not null; - self.last_write_message_id := self.last_write_message_id + SQL%rowcount; commit; end; @@ -57,7 +55,7 @@ create or replace type body ut_output_table_buffer is pragma autonomous_transaction; begin if a_text is not null and a_text != empty_clob() or a_item_type is not null then - if length(a_text) > ut_utils.gc_max_storage_varchar2_len then + if ut_utils.lengthb_clob(a_text) > ut_utils.gc_max_storage_varchar2_len then self.send_lines( ut_utils.convert_collection( ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len) @@ -65,9 +63,8 @@ create or replace type body ut_output_table_buffer is a_item_type ); else - self.last_write_message_id := self.last_write_message_id + 1; insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type) - values (self.output_id, self.last_write_message_id, a_text, a_item_type); + values (self.output_id, ut_output_buffer_tmp_seq.nextval, a_text, a_item_type); end if; commit; end if; @@ -99,7 +96,6 @@ create or replace type body ut_output_table_buffer is l_buffer_texts ut_varchar2_rows; l_buffer_item_types ut_varchar2_rows; l_finished_flags ut_integer_list; - l_last_read_message_id integer; l_already_waited_sec number(10,2) := 0; l_finished boolean := false; l_sleep_time number(2,1); @@ -108,7 +104,6 @@ create or replace type body ut_output_table_buffer is l_producer_finished boolean := false; procedure get_data_from_buffer_table( - a_last_read_message_id in out nocopy integer, a_buffer_texts out nocopy ut_varchar2_rows, a_buffer_item_types out nocopy ut_varchar2_rows, a_finished_flags out nocopy ut_integer_list @@ -116,17 +111,15 @@ create or replace type body ut_output_table_buffer is lc_bulk_limit constant integer := 20000; pragma autonomous_transaction; begin - a_last_read_message_id := coalesce(a_last_read_message_id,0); delete /*+ no_parallel */ from ( select /*+ no_parallel */ * - from ut_output_buffer_tmp o - where o.output_id = self.output_id - and o.message_id <= a_last_read_message_id + lc_bulk_limit - order by o.message_id + from ut_output_buffer_tmp a + where a.output_id = self.output_id + and a.message_id <= (select min(message_id) from ut_output_buffer_tmp o where o.output_id = self.output_id) + lc_bulk_limit + order by a.message_id ) d returning d.text, d.item_type, d.is_finished bulk collect into a_buffer_texts, a_buffer_item_types, a_finished_flags; - a_last_read_message_id := a_last_read_message_id + a_finished_flags.count; commit; end; begin @@ -134,7 +127,7 @@ create or replace type body ut_output_table_buffer is l_sleep_time := case when l_already_waited_sec >= 1 then 0.5 else 0.1 end; l_lock_status := self.get_lock_status(); - get_data_from_buffer_table( l_last_read_message_id, l_buffer_texts, l_buffer_item_types, l_finished_flags ); + get_data_from_buffer_table( l_buffer_texts, l_buffer_item_types, l_finished_flags ); if l_buffer_texts.count > 0 then l_already_waited_sec := 0; diff --git a/source/core/ut_utils.pkb b/source/core/ut_utils.pkb index f29e3b188..81d47221b 100644 --- a/source/core/ut_utils.pkb +++ b/source/core/ut_utils.pkb @@ -92,8 +92,8 @@ create or replace package body ut_utils is a_max_output_len in number := gc_max_output_string_length ) return varchar2 is l_result varchar2(32767); - c_length constant integer := coalesce( length( a_value ), 0 ); - c_max_input_string_length constant integer := a_max_output_len - coalesce( length( a_quote_char ) * 2, 0 ); + c_length constant integer := coalesce( lengthb( a_value ), 0 ); + c_max_input_string_length constant integer := a_max_output_len - coalesce( lengthb( a_quote_char ) * 2, 0 ); c_overflow_substr_len constant integer := c_max_input_string_length - gc_more_data_string_len; begin if c_length = 0 then @@ -112,8 +112,8 @@ create or replace package body ut_utils is a_max_output_len in number := gc_max_output_string_length ) return varchar2 is l_result varchar2(32767); - c_length constant integer := coalesce(dbms_lob.getlength(a_value), 0); - c_max_input_string_length constant integer := a_max_output_len - coalesce( length( a_quote_char ) * 2, 0 ); + c_length constant integer := coalesce(ut_utils.lengthb_clob(a_value), 0); + c_max_input_string_length constant integer := a_max_output_len - coalesce( lengthb( a_quote_char ) * 2, 0 ); c_overflow_substr_len constant integer := c_max_input_string_length - gc_more_data_string_len; begin if a_value is null then @@ -135,7 +135,7 @@ create or replace package body ut_utils is ) return varchar2 is l_result varchar2(32767); c_length constant integer := coalesce(dbms_lob.getlength(a_value), 0); - c_max_input_string_length constant integer := a_max_output_len - coalesce( length( a_quote_char ) * 2, 0 ); + c_max_input_string_length constant integer := a_max_output_len - coalesce( lengthb( a_quote_char ) * 2, 0 ); c_overflow_substr_len constant integer := c_max_input_string_length - gc_more_data_string_len; begin if a_value is null then @@ -412,7 +412,7 @@ create or replace package body ut_utils is if a_list is null then a_list := ut_varchar2_rows(); end if; - if length(a_item) > gc_max_storage_varchar2_len then + if lengthb(a_item) > gc_max_storage_varchar2_len then append_to_list( a_list, ut_utils.convert_collection( @@ -468,7 +468,7 @@ create or replace package body ut_utils is l_result := ut_varchar2_rows(); for i in 1 .. a_collection.count loop l_result.extend(); - l_result(i) := substr(a_collection(i),1,gc_max_storage_varchar2_len); + l_result(i) := substrb(a_collection(i),1,gc_max_storage_varchar2_len); end loop; end if; return l_result; @@ -990,5 +990,39 @@ create or replace package body ut_utils is return l_result; end; + + + /* + * Inspired by + * https://stackoverflow.com/a/48782891 + */ + function lengthb_clob( a_clob clob) return integer is + l_blob blob; + l_desc_offset PLS_INTEGER := 1; + l_src_offset PLS_INTEGER := 1; + l_lang PLS_INTEGER := 0; + l_warning PLS_INTEGER := 0; + l_result integer; + begin + if a_clob = empty_clob() then + l_result := 0; + elsif a_clob is not null then + dbms_lob.createtemporary(l_blob,true); + dbms_lob.converttoblob + ( l_blob + , a_clob + , dbms_lob.getlength(a_clob) + , l_desc_offset + , l_src_offset + , dbms_lob.default_csid + , l_lang + , l_warning + ); + l_result := length(l_blob); + dbms_lob.freetemporary(l_blob); + end if; + return l_result; + end; + end ut_utils; / diff --git a/source/core/ut_utils.pks b/source/core/ut_utils.pks index 90c165bbb..ee5ed7876 100644 --- a/source/core/ut_utils.pks +++ b/source/core/ut_utils.pks @@ -476,6 +476,11 @@ create or replace package ut_utils authid definer is * Return value of interval in plain english */ function interval_to_text(a_interval yminterval_unconstrained) return varchar2; + + /* + * Return length of CLOB in bytes. Null for NULL + */ + function lengthb_clob( a_clob clob) return integer; end ut_utils; / diff --git a/source/uninstall_objects.sql b/source/uninstall_objects.sql index f488b8b8d..a0b53ba21 100644 --- a/source/uninstall_objects.sql +++ b/source/uninstall_objects.sql @@ -333,8 +333,12 @@ drop type ut_output_buffer_base force; drop table ut_output_buffer_tmp purge; +drop table ut_output_buffer_tmp_seq purge; + drop table ut_output_clob_buffer_tmp purge; +drop table ut_output_clob_buffer_tmp_seq purge; + drop table ut_output_buffer_info_tmp purge; drop package ut_session_context; diff --git a/test/ut3_tester/core/test_output_buffer.pkb b/test/ut3_tester/core/test_output_buffer.pkb index edb10e3e6..317e7e3d5 100644 --- a/test/ut3_tester/core/test_output_buffer.pkb +++ b/test/ut3_tester/core/test_output_buffer.pkb @@ -56,8 +56,8 @@ create or replace package body test_output_buffer is procedure test_doesnt_send_on_null_elem is - l_cur sys_refcursor; - l_result integer; + l_actual sys_refcursor; + l_expected sys_refcursor; l_buffer ut3_develop.ut_output_buffer_base := ut3_develop.ut_output_table_buffer(); l_message_id varchar2(255); l_text varchar2(4000); @@ -67,9 +67,12 @@ create or replace package body test_output_buffer is l_buffer.send_lines(ut3_develop.ut_varchar2_rows(null)); l_buffer.send_lines(ut3_develop.ut_varchar2_rows('test')); - select message_id, text into l_message_id, l_text from table(ut3_tester_helper.run_helper.ut_output_buffer_tmp); - ut.expect(l_message_id).to_equal('1'); - ut.expect(l_text).to_equal('test'); + open l_actual for + select text from table(ut3_tester_helper.run_helper.ut_output_buffer_tmp); + open l_expected for + select 'test' as text from dual; + + ut.expect(l_actual).to_equal(l_expected); end; procedure test_send_line is @@ -157,5 +160,41 @@ create or replace package body test_output_buffer is test_purge(ut3_develop.ut_output_clob_table_buffer()); end; -end test_output_buffer; + procedure text_buffer_send_multibyte is + l_input varchar2(32767); + l_max_len integer := ut3_develop.ut_utils.gc_max_storage_varchar2_len; + l_buffer ut3_develop.ut_output_buffer_base := ut3_develop.ut_output_table_buffer(); + l_text varchar2(4000); + begin + --Arrange + ut3_tester_helper.run_helper.delete_buffer(); + l_input := rpad( '❤', l_max_len, 'a' ); + ut.expect( lengthb( l_input ) ).to_be_greater_than(l_max_len); + + --Act + l_buffer.send_line(l_input); + --Assert + select text into l_text from table(ut3_tester_helper.run_helper.ut_output_buffer_tmp); + ut.expect(lengthb(l_text)).to_be_less_or_equal(l_max_len); + end; + + procedure text_buffer_send_clob_multib is + l_input clob; + l_max_len integer := ut3_develop.ut_utils.gc_max_storage_varchar2_len; + l_buffer ut3_develop.ut_output_buffer_base := ut3_develop.ut_output_table_buffer(); + l_text varchar2(4000); + begin + --Arrange + ut3_tester_helper.run_helper.delete_buffer(); + l_input := rpad( '❤', l_max_len, 'a' ); + ut.expect( ut3_develop.ut_utils.lengthb_clob( l_input ) ).to_be_greater_than(l_max_len); + + --Act + l_buffer.send_clob(l_input); + --Assert + select text into l_text from table(ut3_tester_helper.run_helper.ut_output_buffer_tmp); + ut.expect(lengthb(l_text)).to_be_less_or_equal(l_max_len); + end; + + end test_output_buffer; / diff --git a/test/ut3_tester/core/test_output_buffer.pks b/test/ut3_tester/core/test_output_buffer.pks index feaa337f8..5b6cd678b 100644 --- a/test/ut3_tester/core/test_output_buffer.pks +++ b/test/ut3_tester/core/test_output_buffer.pks @@ -47,5 +47,11 @@ create or replace package test_output_buffer is --%test(Purges clob buffer data older than one day and leaves the rest) procedure test_purge_clob_buffer; + --%test(Successfully sends multibyte long line into text buffer) + procedure text_buffer_send_multibyte; + + --%test(Successfully sends multibyte long clob line into text buffer) + procedure text_buffer_send_clob_multib; + end test_output_buffer; / diff --git a/test/ut3_tester/core/test_ut_utils.pkb b/test/ut3_tester/core/test_ut_utils.pkb index ec7e4f403..27c164e4e 100644 --- a/test/ut3_tester/core/test_ut_utils.pkb +++ b/test/ut3_tester/core/test_ut_utils.pkb @@ -489,5 +489,23 @@ end; ut.expect(l_expected).to_equal(l_actual); end; + procedure convert_collection_multibyte is + l_input ut3_develop.ut_varchar2_list; + l_max_len integer := ut3_develop.ut_utils.gc_max_storage_varchar2_len; + begin + --Arrange + l_input := ut3_develop.ut_varchar2_list( rpad( '❤', l_max_len, 'a' ) ); + ut.expect( lengthb( l_input( 1 ) ) ).to_be_greater_than(l_max_len); + + --Act + ut.expect( lengthb( ut3_develop.ut_utils.convert_collection(l_input)(1) ) ).to_be_less_or_equal(l_max_len); + end; + + procedure lengthb_gives_length_in_bytes is + l_clob clob; + begin + l_clob := '❤'; + ut.expect(ut3_develop.ut_utils.lengthb_clob(l_clob)).to_equal(3); + end; end test_ut_utils; / diff --git a/test/ut3_tester/core/test_ut_utils.pks b/test/ut3_tester/core/test_ut_utils.pks index 114b35e86..ca2e7b304 100644 --- a/test/ut3_tester/core/test_ut_utils.pks +++ b/test/ut3_tester/core/test_ut_utils.pks @@ -152,10 +152,15 @@ create or replace package test_ut_utils is procedure int_conv_ym_month; --%test(returns text representation of interval year to month for custom interval) - procedure int_conv_ym_date; - - + procedure int_conv_ym_date; + --%endcontext - + + --%test(convert_collection does not fail on multibyte strings - Issue #1245 ) + procedure convert_collection_multibyte; + + --%test(lengthb returns length of a CLOB in bytes ) + procedure lengthb_gives_length_in_bytes; + end test_ut_utils; / From b70ee1e742652da3c4a13231e1edcc26ecff5998 Mon Sep 17 00:00:00 2001 From: Jacek Gebal Date: Sun, 28 May 2023 17:03:28 +0300 Subject: [PATCH 2/2] Fixed failing unit test and the uninstall script --- source/uninstall_objects.sql | 4 ++-- test/ut3_tester/core/test_ut_utils.pkb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/uninstall_objects.sql b/source/uninstall_objects.sql index a0b53ba21..dde9a824f 100644 --- a/source/uninstall_objects.sql +++ b/source/uninstall_objects.sql @@ -333,11 +333,11 @@ drop type ut_output_buffer_base force; drop table ut_output_buffer_tmp purge; -drop table ut_output_buffer_tmp_seq purge; +drop sequence ut_output_buffer_tmp_seq; drop table ut_output_clob_buffer_tmp purge; -drop table ut_output_clob_buffer_tmp_seq purge; +drop sequence ut_output_clob_buffer_tmp_seq; drop table ut_output_buffer_info_tmp purge; diff --git a/test/ut3_tester/core/test_ut_utils.pkb b/test/ut3_tester/core/test_ut_utils.pkb index 27c164e4e..433987c01 100644 --- a/test/ut3_tester/core/test_ut_utils.pkb +++ b/test/ut3_tester/core/test_ut_utils.pkb @@ -505,7 +505,7 @@ end; l_clob clob; begin l_clob := '❤'; - ut.expect(ut3_develop.ut_utils.lengthb_clob(l_clob)).to_equal(3); + ut.expect(ut3_develop.ut_utils.lengthb_clob(l_clob)).to_be_greater_than(1); end; end test_ut_utils; /