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

Skip to content

Commit 6f38cd5

Browse files
committed
tmp.
1 parent 2bf6506 commit 6f38cd5

7 files changed

Lines changed: 214 additions & 63 deletions

File tree

source/expectations/data_values/ut_data_value_refcursor.tpb

Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,22 @@ create or replace type body ut_data_value_refcursor as
2828
end;
2929

3030
member procedure init(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor) is
31+
c_bulk_rows constant integer := 1000;
32+
l_cursor sys_refcursor := a_value;
3133
l_ctx number;
3234
l_xml xmltype;
33-
c_bulk_rows constant integer := 1000;
3435
l_current_date_format varchar2(4000);
35-
l_ut_owner varchar2(250) := ut_utils.ut_owner;
36-
cursor_not_open exception;
36+
l_ut_owner varchar2(250) := ut_utils.ut_owner;
37+
cursor_not_open exception;
3738
begin
3839
self.is_cursor_null := ut_utils.boolean_to_int(a_value is null);
3940
self.self_type := $$plsql_unit;
4041
self.data_set_guid := sys_guid();
4142
self.data_type := 'refcursor';
42-
self.columns_info := ut_refcursor_descriptor.get_columns_info(a_value);
43-
if a_value is not null then
44-
if a_value%isopen then
45-
self.row_count := 0;
43+
if l_cursor is not null then
44+
if l_cursor%isopen then
45+
self.columns_info := ut_refcursor_helper.get_columns_info(l_cursor);
46+
self.row_count := 0;
4647
-- We use DBMS_XMLGEN in order to:
4748
-- 1) be able to process data in bulks (set of rows)
4849
-- 2) be able to influence the ROWSET/ROW tags
@@ -56,15 +57,17 @@ create or replace type body ut_data_value_refcursor as
5657
-- The restartQuery fails however if PLSQL variables of TIMESTAMP/INTERVAL or CLOB/BLOB are used.
5758

5859
ut_expectation_processor.set_xml_nls_params();
59-
l_ctx := dbms_xmlgen.newContext(a_value);
60+
l_ctx := dbms_xmlgen.newContext(l_cursor);
6061
dbms_xmlgen.setNullHandling(l_ctx, dbms_xmlgen.empty_tag);
6162
dbms_xmlgen.setMaxRows(l_ctx, c_bulk_rows);
6263

6364
loop
6465
l_xml := dbms_xmlgen.getxmltype(l_ctx);
6566

66-
execute immediate 'insert into ' || l_ut_owner || '.ut_data_set_tmp(data_set_guid, item_no, item_data)
67-
select :self_guid, :self_row_count + rownum, value(a) from table( xmlsequence( extract(:l_xml,''ROWSET/*'') ) ) a'
67+
execute immediate
68+
'insert into ' || l_ut_owner || '.ut_data_set_tmp(data_set_guid, item_no, item_data) ' ||
69+
'select :self_guid, :self_row_count + rownum, value(a) ' ||
70+
' from table( xmlsequence( extract(:l_xml,''ROWSET/*'') ) ) a'
6871
using in self.data_set_guid, self.row_count, l_xml;
6972

7073
exit when sql%rowcount = 0;
@@ -73,12 +76,12 @@ create or replace type body ut_data_value_refcursor as
7376
end loop;
7477

7578
ut_expectation_processor.reset_nls_params();
76-
if a_value%isopen then
77-
close a_value;
79+
if l_cursor%isopen then
80+
close l_cursor;
7881
end if;
7982
dbms_xmlgen.closeContext(l_ctx);
8083

81-
elsif not a_value%isopen then
84+
elsif not l_cursor%isopen then
8285
raise cursor_not_open;
8386
end if;
8487
end if;
@@ -87,8 +90,8 @@ create or replace type body ut_data_value_refcursor as
8790
raise_application_error(-20155, 'Cursor is not open');
8891
when others then
8992
ut_expectation_processor.reset_nls_params();
90-
if a_value%isopen then
91-
close a_value;
93+
if l_cursor%isopen then
94+
close l_cursor;
9295
end if;
9396
dbms_xmlgen.closeContext(l_ctx);
9497
raise;
@@ -105,19 +108,25 @@ create or replace type body ut_data_value_refcursor as
105108
l_result clob;
106109
l_result_string varchar2(32767);
107110
begin
108-
dbms_lob.createtemporary(l_result,true);
109-
--return first 10 rows
110-
execute immediate '
111-
select xmlserialize( content ucd.item_data no indent)
112-
from '|| ut_utils.ut_owner ||'.ut_data_set_tmp ucd
113-
where ucd.data_set_guid = :data_set_guid
114-
and ucd.item_no <= :max_rows'
115-
bulk collect into l_results using self.data_set_guid, c_max_rows;
116-
117-
ut_utils.append_to_clob(l_result,l_results);
118-
119-
l_result_string := ut_utils.to_string(l_result,null);
120-
dbms_lob.freetemporary(l_result);
111+
if not self.is_null() then
112+
dbms_lob.createtemporary(l_result,true);
113+
ut_utils.append_to_clob(l_result,'Data-types:'||chr(10));
114+
ut_utils.append_to_clob(l_result,self.columns_info.getclobval());
115+
116+
ut_utils.append_to_clob(l_result,chr(10)||'Data:'||chr(10));
117+
--return first c_max_rows rows
118+
execute immediate '
119+
select xmlserialize( content ucd.item_data no indent)
120+
from '|| ut_utils.ut_owner ||'.ut_data_set_tmp ucd
121+
where ucd.data_set_guid = :data_set_guid
122+
and ucd.item_no <= :max_rows'
123+
bulk collect into l_results using self.data_set_guid, c_max_rows;
124+
125+
ut_utils.append_to_clob(l_result,l_results);
126+
127+
l_result_string := ut_utils.to_string(l_result,null);
128+
dbms_lob.freetemporary(l_result);
129+
end if;
121130
return l_result_string;
122131
end;
123132

@@ -173,30 +182,41 @@ create or replace type body ut_data_value_refcursor as
173182
end;
174183

175184
member function compare_implementation(a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2) return integer is
176-
l_result integer;
177-
l_other ut_data_value_refcursor;
178-
l_ut_owner varchar2(250) := ut_utils.ut_owner;
179-
l_column_filter varchar2(32767);
180-
l_diff_id raw(16);
185+
l_result integer := 0;
186+
l_other ut_data_value_refcursor;
187+
l_ut_owner varchar2(250) := ut_utils.ut_owner;
188+
l_column_filter varchar2(32767);
189+
l_diff_id raw(16);
190+
function columns_hash(
191+
a_data_value_cursor ut_data_value_refcursor, a_exclude_xpath varchar2, a_include_xpath varchar2
192+
) return raw is
193+
l_cols_hash raw(32);
194+
begin
195+
if not a_data_value_cursor.is_null then
196+
execute immediate
197+
q'[select dbms_crypto.hash(replace(x.item_data.getclobval(),'>CHAR<','>VARCHAR2<'),3) ]' ||
198+
' from ( select '||ut_refcursor_helper.get_columns_filter(a_exclude_xpath, a_include_xpath)||
199+
' from (select :columns_info as item_data from dual ) ucd' ||
200+
' ) x'
201+
into l_cols_hash using a_exclude_xpath, a_include_xpath, a_data_value_cursor.columns_info;
202+
end if;
203+
return l_cols_hash;
204+
end;
181205
begin
182-
-- this SQL statement is constructed in a way that we always get the same number and ordering of substitution variables
183-
-- That is, we always get: l_exclude_xpath, l_include_xpath
184-
-- regardless if the variables are NULL (not to be used) or NOT NULL and will be used for filtering
185-
if a_exclude_xpath is null and a_include_xpath is null then
186-
l_column_filter := ':l_exclude_xpath as l_exclude_xpath, :l_include_xpath as l_include_xpath, ucd.item_data as item_data';
187-
elsif a_exclude_xpath is not null and a_include_xpath is null then
188-
l_column_filter := 'deletexml( ucd.item_data, :l_exclude_xpath ) as item_data, :l_include_xpath as l_include_xpath';
189-
elsif a_exclude_xpath is null and a_include_xpath is not null then
190-
l_column_filter := ':l_exclude_xpath as l_exclude_xpath, extract( ucd.item_data, :l_include_xpath ) as item_data';
191-
elsif a_exclude_xpath is not null and a_include_xpath is not null then
192-
l_column_filter := 'extract( deletexml( ucd.item_data, :l_exclude_xpath ), :l_include_xpath ) as item_data';
193-
end if;
194206
if not a_other is of (ut_data_value_refcursor) then
195207
raise value_error;
196208
end if;
197209

198210
l_other := treat(a_other as ut_data_value_refcursor);
211+
212+
--if column names/types are not equal - build a diff of column names and types
213+
if columns_hash( self, a_exclude_xpath, a_include_xpath )
214+
!= columns_hash( l_other, a_exclude_xpath, a_include_xpath )
215+
then
216+
l_result := 1;
217+
end if;
199218
l_diff_id := dbms_crypto.hash(self.data_set_guid||l_other.data_set_guid,2);
219+
l_column_filter := ut_refcursor_helper.get_columns_filter(a_exclude_xpath, a_include_xpath);
200220
-- Find differences
201221
execute immediate 'insert into ' || l_ut_owner || '.ut_data_set_diff_tmp ( diff_id, item_no )
202222
select :diff_id, nvl(exp.item_no, act.item_no)
@@ -210,7 +230,7 @@ create or replace type body ut_data_value_refcursor as
210230
using in l_diff_id, a_exclude_xpath, a_include_xpath, self.data_set_guid, a_exclude_xpath, a_include_xpath, l_other.data_set_guid;
211231

212232
--result is OK only if both are same
213-
if sql%rowcount = 0 and self.row_count = l_other.row_count then
233+
if sql%rowcount = 0 and self.row_count = l_other.row_count and l_result = 0 then
214234
l_result := 0;
215235
else
216236
l_result := 1;

source/expectations/data_values/ut_data_value_refcursor.tps

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ create or replace type ut_data_value_refcursor under ut_data_value(
3838
/**
3939
* Holds information about column names and column data-types
4040
*/
41-
columns_info ut_key_value_pairs,
41+
columns_info xmltype,
4242

4343
constructor function ut_data_value_refcursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor) return self as result,
4444
member procedure init(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor),

source/expectations/data_values/ut_refcursor_descriptor.pkb renamed to source/expectations/data_values/ut_refcursor_helper.pkb

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
create or replace package body ut_refcursor_descriptor is
1+
create or replace package body ut_refcursor_helper is
22
/*
33
utPLSQL - Version 3
44
Copyright 2016 - 2017 utPLSQL Project
@@ -40,20 +40,48 @@ create or replace package body ut_refcursor_descriptor is
4040
return l_result;
4141
end;
4242

43-
function get_columns_info(a_cursor in out nocopy sys_refcursor) return ut_key_value_pairs is
44-
l_cursor_number integer;
43+
function get_columns_info(a_cursor in out nocopy sys_refcursor) return xmltype is
44+
l_cursor_number integer;
4545
l_columns_count pls_integer;
4646
l_columns_desc dbms_sql.desc_tab3;
47+
l_result xmltype;
48+
l_columns_tab ut_key_value_pairs;
4749
begin
4850
if a_cursor is null or not a_cursor%isopen then
49-
return ut_key_value_pairs();
51+
return null;
5052
end if;
5153
l_cursor_number := dbms_sql.to_cursor_number( a_cursor );
5254
dbms_sql.describe_columns3( l_cursor_number, l_columns_count, l_columns_desc );
5355
a_cursor := dbms_sql.to_refcursor( l_cursor_number );
54-
return get_columns_info( l_columns_desc, l_columns_count);
56+
l_columns_tab := get_columns_info( l_columns_desc, l_columns_count);
57+
58+
select XMLELEMENT("ROW", xmlagg(xmlelement(evalname key, value))) into l_result from table(l_columns_tab );
59+
60+
return l_result;
5561
end;
5662

63+
function get_columns_filter(
64+
a_exclude_xpath varchar2, a_include_xpath varchar2,
65+
a_table_alias varchar2 := 'ucd', a_column_alias varchar2 := 'item_data'
66+
) return varchar2 is
67+
l_filter varchar2(32767);
68+
l_source_column varchar2(500) := a_table_alias||'.'||a_column_alias;
69+
begin
70+
-- this SQL statement is constructed in a way that we always get the same number and ordering of substitution variables
71+
-- That is, we always get: l_exclude_xpath, l_include_xpath
72+
-- regardless if the variables are NULL (not to be used) or NOT NULL and will be used for filtering
73+
if a_exclude_xpath is null and a_include_xpath is null then
74+
l_filter := ':l_exclude_xpath, :l_include_xpath, '||l_source_column||' as '||a_column_alias;
75+
elsif a_exclude_xpath is not null and a_include_xpath is null then
76+
l_filter := 'deletexml( '||l_source_column||', :l_exclude_xpath ) as '||a_column_alias||', :l_include_xpath';
77+
elsif a_exclude_xpath is null and a_include_xpath is not null then
78+
l_filter := ':l_exclude_xpath, extract( '||l_source_column||', :l_include_xpath ) as '||a_column_alias;
79+
elsif a_exclude_xpath is not null and a_include_xpath is not null then
80+
l_filter := 'extract( deletexml( '||l_source_column||', :l_exclude_xpath ), :l_include_xpath ) as '||a_column_alias;
81+
end if;
82+
return l_filter;
83+
end;
84+
5785
begin
5886
g_type_name_map( dbms_sql.binary_bouble_type ) := 'BINARY_DOUBLE';
5987
g_type_name_map( dbms_sql.bfile_type ) := 'BFILE';

source/expectations/data_values/ut_refcursor_descriptor.pks renamed to source/expectations/data_values/ut_refcursor_helper.pks

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
create or replace package ut_refcursor_descriptor is
1+
create or replace package ut_refcursor_helper is
22
/*
33
utPLSQL - Version 3
44
Copyright 2016 - 2017 utPLSQL Project
@@ -15,7 +15,13 @@ create or replace package ut_refcursor_descriptor is
1515
See the License for the specific language governing permissions and
1616
limitations under the License.
1717
*/
18-
function get_columns_info(a_cursor in out nocopy sys_refcursor) return ut_key_value_pairs;
18+
19+
function get_columns_info(a_cursor in out nocopy sys_refcursor) return xmltype;
20+
21+
function get_columns_filter(
22+
a_exclude_xpath varchar2, a_include_xpath varchar2,
23+
a_table_alias varchar2 := 'ucd', a_column_alias varchar2 := 'item_data'
24+
) return varchar2;
1925

2026
end;
2127
/

source/install.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ prompt Installing PLSQL profiler objects into &&ut3_owner schema
138138
--expectations and matchers
139139
@@install_component.sql 'expectations/data_values/ut_data_set_tmp.sql'
140140
@@install_component.sql 'expectations/data_values/ut_data_set_diff_tmp.sql'
141+
@@install_component.sql 'expectations/data_values/ut_refcursor_helper.pks'
142+
@@install_component.sql 'expectations/data_values/ut_refcursor_helper.pkb'
141143
@@install_component.sql 'expectations/data_values/ut_data_value.tps'
142144
@@install_component.sql 'expectations/data_values/ut_data_value_anydata.tps'
143145
@@install_component.sql 'expectations/data_values/ut_data_value_collection.tps'

0 commit comments

Comments
 (0)