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

Skip to content

Commit 3ca16f7

Browse files
committed
Updated JoinBy query
1 parent bcab19c commit 3ca16f7

5 files changed

Lines changed: 164 additions & 69 deletions

File tree

source/expectations/data_values/ut_compound_data_helper.pkb

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -167,68 +167,76 @@ create or replace package body ut_compound_data_helper is
167167
) return tt_row_diffs is
168168
l_column_filter varchar2(32767);
169169
l_results tt_row_diffs;
170-
l_sql varchar2(32767); -- REMOVE LATER also for unorder
171170
begin
172171
l_column_filter := get_columns_filter(a_exclude_xpath,a_include_xpath);
173172

174173
/**
175174
* Since its unordered search we cannot select max rows from diffs as we miss some comparision records
176175
* We will restrict output on higher level of select
177-
*/
176+
**/
178177

179-
l_sql := q'[
180-
with
181-
diff_info as (select item_hash from ut_compound_data_diff_tmp ucdc where diff_id = :diff_guid)
178+
execute immediate q'[
179+
with diff_info as (select item_hash from ut_compound_data_diff_tmp ucdc where diff_id = :diff_guid)
182180
select rn,diff_type,diffed_row
183-
from (select dense_rank() over (order by pk_hash) as rn, diff_type,data_item diffed_row
184-
from (select nvl(exp.pk_hash, act.pk_hash) pk_hash,
185-
xmlserialize(content exp.row_data no indent) exp_item,
186-
xmlserialize(content act.row_data no indent) act_item
187-
from
188-
(select ucd.*, row_number() over(partition by pk_hash order by row_hash) duplicate_no
189-
from
190-
(select ucd.column_value row_data,
191-
dbms_crypto.hash( value(ucd).getclobval(),3) row_hash,
192-
dbms_crypto.hash( extract(value(ucd),']'|| a_join_by_xpath ||q'[').getClobVal(),3/*HASH_SH1*/) pk_hash
193-
from
194-
(select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_data item_data_no_filter
195-
from ut_compound_data_tmp ucd
196-
where ucd.data_id = :self_guid
197-
and ucd.item_hash in (select i.item_hash from diff_info i)
198-
) r,
199-
table( xmlsequence( extract(r.item_data,'/*') ) ) ucd
200-
) ucd
201-
) exp
202-
join (
203-
select ucd.*, row_number() over(partition by pk_hash order by row_hash) duplicate_no
204-
from
205-
(select ucd.column_value row_data,
206-
dbms_crypto.hash( value(ucd).getclobval(),3/*HASH_SH1*/) row_hash,
207-
dbms_crypto.hash( extract(value(ucd),']'|| a_join_by_xpath ||q'[').getClobVal(),3/*HASH_SH1*/) pk_hash
208-
from
209-
(select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_data item_data_no_filter
210-
from ut_compound_data_tmp ucd
211-
where ucd.data_id = :other_guid
212-
and ucd.item_hash in (select i.item_hash from diff_info i)
213-
) r,
214-
table( xmlsequence( extract(r.item_data,'/*') ) ) ucd
215-
) ucd
216-
) act
217-
on exp.pk_hash = act.pk_hash and exp.duplicate_no = act.duplicate_no
218-
where exp.row_hash != act.row_hash
219-
or exp.row_hash is null
220-
or act.row_hash is null
221-
)
222-
unpivot ( data_item for diff_type in (exp_item as 'Expected:', act_item as 'Actual:') )
223-
)
224-
where rownum < :max_rows
225-
order by 1, 2]';
226-
227-
execute immediate l_sql
181+
from
182+
(select dense_rank() over (order by pk_hash) as rn, diff_type,data_item diffed_row
183+
from
184+
(select pk_hash
185+
,case when exp_item is not null and act_item is not null then exp_item else null end exp_item
186+
,case when exp_item is not null and act_item is not null then act_item else null end act_item
187+
,case when exp_item is not null and act_item is null then exp_item else null end miss_item
188+
,case when exp_item is null and act_item is not null then act_item else null end ext_item
189+
from
190+
(select nvl(exp.pk_hash, act.pk_hash) pk_hash,
191+
xmlserialize(content exp.row_data no indent) exp_item,
192+
xmlserialize(content act.row_data no indent) act_item
193+
from
194+
(select ucd.*, row_number() over(partition by pk_hash order by row_hash) duplicate_no
195+
from
196+
(select ucd.column_value row_data,
197+
dbms_crypto.hash( value(ucd).getclobval(),3) row_hash,
198+
dbms_crypto.hash( extract(value(ucd), :join_by_xpath ).getClobVal(),3/*HASH_SH1*/) pk_hash
199+
from
200+
(select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_data item_data_no_filter
201+
from ut_compound_data_tmp ucd
202+
where ucd.data_id = :self_guid
203+
and ucd.item_hash in (select i.item_hash from diff_info i)
204+
) r,
205+
table( xmlsequence( extract(r.item_data,'/*') ) ) ucd
206+
) ucd
207+
) exp
208+
full outer join (
209+
select ucd.*, row_number() over(partition by pk_hash order by row_hash) duplicate_no
210+
from
211+
(select ucd.column_value row_data,
212+
dbms_crypto.hash( value(ucd).getclobval(),3/*HASH_SH1*/) row_hash,
213+
dbms_crypto.hash( extract(value(ucd), :join_by_xpath ).getClobVal(),3/*HASH_SH1*/) pk_hash
214+
from
215+
(select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_data item_data_no_filter
216+
from ut_compound_data_tmp ucd
217+
where ucd.data_id = :other_guid
218+
and ucd.item_hash in (select i.item_hash from diff_info i)
219+
) r,
220+
table( xmlsequence( extract(r.item_data,'/*') ) ) ucd
221+
) ucd
222+
) act
223+
on exp.pk_hash = act.pk_hash and exp.duplicate_no = act.duplicate_no
224+
where (exp.row_hash != act.row_hash and act.pk_hash = exp.pk_hash) or
225+
(
226+
(exp.pk_hash is null or act.pk_hash is null) and
227+
(exp.row_hash is null or act.row_hash is null)
228+
)
229+
)
230+
)
231+
unpivot ( data_item for diff_type in (exp_item as 'Expected:', act_item as 'Actual:'
232+
,miss_item as 'Missing:', ext_item as 'Extra:') )
233+
)
234+
where rownum <= :max_rows
235+
order by 1, 2]'
228236
bulk collect into l_results
229237
using a_diff_id,
230-
a_exclude_xpath, a_include_xpath, a_expected_dataset_guid,
231-
a_exclude_xpath, a_include_xpath, a_actual_dataset_guid,
238+
a_join_by_xpath,a_exclude_xpath, a_include_xpath, a_expected_dataset_guid,
239+
a_join_by_xpath,a_exclude_xpath, a_include_xpath, a_actual_dataset_guid,
232240
a_max_rows;
233241
return l_results;
234242
end;
@@ -325,8 +333,8 @@ create or replace package body ut_compound_data_helper is
325333
coalesce(exp.duplicate_no,act.duplicate_no) duplicate_no,
326334
case
327335
when act.row_hash is null then
328-
'miss row'
329-
else 'extra row'
336+
'Missing:'
337+
else 'Extra:'
330338
end diffed_type,
331339
case when exp.row_hash is null then
332340
xmlserialize(content act.row_data no indent)

source/expectations/data_values/ut_compound_data_value.tpb

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,10 @@ create or replace type body ut_compound_data_value as
155155
execute immediate 'select count(*) from ' || l_ut_owner || '.ut_compound_data_diff_tmp where diff_id = :diff_id' into l_diff_row_count using l_diff_id;
156156

157157
if l_diff_row_count > 0 then
158-
if a_join_by_xpath is not null then
158+
if a_join_by_xpath is not null then
159159
l_row_diffs := ut_compound_data_helper.get_rows_diff(
160160
self.data_id, l_actual.data_id, l_diff_id, c_max_rows, a_exclude_xpath, a_include_xpath, a_join_by_xpath
161-
);
161+
);
162162
else
163163
l_row_diffs := ut_compound_data_helper.get_rows_diff(
164164
self.data_id, l_actual.data_id, l_diff_id, c_max_rows, a_exclude_xpath, a_include_xpath
@@ -253,34 +253,36 @@ create or replace type body ut_compound_data_value as
253253

254254
l_diff_id := ut_compound_data_helper.get_hash(self.data_id||l_other.data_id);
255255
l_column_filter := ut_compound_data_helper.get_columns_filter(a_exclude_xpath, a_include_xpath);
256-
256+
257257
-- Pre generate hash minus to leave only onese that are diffrent, for example duplicates or diffrent hash
258258
execute immediate 'insert into ' || l_ut_owner || '.ut_compound_data_diff_tmp ( diff_id,item_hash,duplicate_no )
259259
select :diff_id,x.item_hash,tmp.duplicate_no
260260
from(
261261
(
262262
select item_hash,row_number() over (partition by item_hash,data_id order by 1) duplicate_no
263-
from ut_compound_data_tmp
263+
from ' || l_ut_owner || '.ut_compound_data_tmp
264264
where data_id = :self_guid
265265
minus
266266
select item_hash,row_number() over (partition by item_hash,data_id order by 1)
267-
from ut_compound_data_tmp
267+
from ' || l_ut_owner || '.ut_compound_data_tmp
268268
where data_id = :other_guid
269269
)
270270
union all
271271
(
272272
select item_hash,row_number() over (partition by item_hash,data_id order by 1)
273-
from ut_compound_data_tmp
273+
from ' || l_ut_owner || '.ut_compound_data_tmp
274274
where data_id = :other_guid
275275
minus
276276
select item_hash,row_number() over (partition by item_hash,data_id order by 1)
277-
from ut_compound_data_tmp
277+
from ' || l_ut_owner || '.ut_compound_data_tmp
278278
where data_id = :self_guid
279279
))tmp
280-
,ut_compound_data_tmp x
281-
where tmp.item_hash = x.item_hash'
280+
, ' || l_ut_owner || '.ut_compound_data_tmp x
281+
where tmp.item_hash = x.item_hash
282+
and x.data_id in (:self_guid,:other_guid)'
282283
using l_diff_id, self.data_id, l_other.data_id
283-
,l_other.data_id,self.data_id;
284+
,l_other.data_id,self.data_id,
285+
self.data_id, l_other.data_id;
284286
--result is OK only if both are same
285287
if sql%rowcount = 0 and self.elements_count = l_other.elements_count then
286288
l_result := 0;

source/expectations/data_values/ut_data_value_refcursor.tpb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ create or replace type body ut_data_value_refcursor as
1515
See the License for the specific language governing permissions and
1616
limitations under the License.
1717
*/
18-
18+
1919
constructor function ut_data_value_refcursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor) return self as result is
2020
begin
2121
init(a_value);
@@ -28,8 +28,8 @@ create or replace type body ut_data_value_refcursor as
2828
l_ctx number;
2929
l_xml xmltype;
3030
l_current_date_format varchar2(4000);
31-
l_ut_owner varchar2(250) := ut_utils.ut_owner;
3231
cursor_not_open exception;
32+
l_ut_owner varchar2(250) := ut_utils.ut_owner;
3333
begin
3434
self.is_data_null := ut_utils.boolean_to_int(a_value is null);
3535
self.self_type := $$plsql_unit;
@@ -58,10 +58,10 @@ create or replace type body ut_data_value_refcursor as
5858

5959
loop
6060
l_xml := dbms_xmlgen.getxmltype(l_ctx);
61-
62-
execute immediate
61+
62+
execute immediate
6363
'insert into ' || l_ut_owner || '.ut_compound_data_tmp(data_id, item_no, item_data, item_hash) ' ||
64-
'select :self_guid, :self_row_count + rownum, value(a), dbms_crypto.hash( value(a).getclobval(),3)' ||
64+
'select :self_guid, :self_row_count + rownum, value(a),'||l_ut_owner||'.ut_compound_data_helper.get_hash(value(a).GetClobVal()) ' ||
6565
' from table( xmlsequence( extract(:l_xml,''ROWSET/*'') ) ) a'
6666
using in self.data_id, self.elements_count, l_xml;
6767

test/core/expectations/compound_data/test_expectations_cursor.pkb

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,5 +1041,78 @@ Rows: [ 2 differences ]%
10411041
end;
10421042
end;
10431043

1044+
procedure cursor_unordered_compare_success is
1045+
l_actual SYS_REFCURSOR;
1046+
l_expected SYS_REFCURSOR;
1047+
begin
1048+
--Arrange
1049+
open l_actual for select username , user_id from all_users order by username asc;
1050+
open l_expected for select username , user_id from all_users order by username desc;
1051+
--Act
1052+
ut3.ut.expect(l_actual).to_equal(l_expected).unordered;
1053+
--Assert
1054+
ut.expect(expectations.failed_expectations_data()).to_be_empty();
1055+
end;
1056+
1057+
procedure cursor_unordered_compare_fail is
1058+
l_actual SYS_REFCURSOR;
1059+
l_expected SYS_REFCURSOR;
1060+
l_actual_message varchar2(32767);
1061+
l_expected_message varchar2(32767);
1062+
begin
1063+
--Arrange
1064+
open l_actual for select 'test1' username,-100 user_id from dual
1065+
union all
1066+
select 'test' username,-666 user_id from dual
1067+
order by 1 asc;
1068+
1069+
open l_expected for select 'test1' username,-100 user_id from dual
1070+
union all
1071+
select 'test' username,-667 user_id from dual
1072+
order by 1 desc;
1073+
--Act
1074+
ut3.ut.expect(l_actual).to_equal(l_expected).unordered;
1075+
l_expected_message := q'[%Actual: refcursor [ count = 2 ] was expected to equal: refcursor [ count = 2 ]%
1076+
Diff:%
1077+
Rows: [ 2 differences ]
1078+
Missing: <ROW><USERNAME>test</USERNAME><USER_ID>-667</USER_ID></ROW>%
1079+
Extra: <ROW><USERNAME>test</USERNAME><USER_ID>-666</USER_ID></ROW>%]';
1080+
l_actual_message := ut3.ut_expectation_processor.get_failed_expectations()(1).message;
1081+
--Assert
1082+
ut.expect(l_actual_message).to_be_like(l_expected_message);
1083+
end;
1084+
1085+
procedure cursor_joinby_compare is
1086+
l_actual SYS_REFCURSOR;
1087+
l_expected SYS_REFCURSOR;
1088+
begin
1089+
--Arrange
1090+
open l_actual for select owner, object_name,object_type from all_objects where owner = user
1091+
order by 1,2,3 asc;
1092+
open l_expected for select owner, object_name,object_type from all_objects where owner = user
1093+
order by 1,2,3 desc;
1094+
1095+
--Act
1096+
ut3.ut.expect(l_actual).to_equal(l_expected).join_by('OWNER');
1097+
--Assert
1098+
ut.expect(expectations.failed_expectations_data()).to_be_empty();
1099+
end;
1100+
1101+
procedure cursor_joinby_compare_twocolumns is
1102+
l_actual SYS_REFCURSOR;
1103+
l_expected SYS_REFCURSOR;
1104+
begin
1105+
--Arrange
1106+
open l_actual for select owner, object_name,object_type from all_objects where owner = user
1107+
order by 1,2,3 asc;
1108+
open l_expected for select owner, object_name,object_type from all_objects where owner = user
1109+
order by 1,2,3 desc;
1110+
1111+
--Act
1112+
ut3.ut.expect(l_actual).to_equal(l_expected).join_by(ut3.ut_varchar2_list('OWNER,OBJECT_NAME'));
1113+
--Assert
1114+
ut.expect(expectations.failed_expectations_data()).to_be_empty();
1115+
end;
1116+
10441117
end;
10451118
/

test/core/expectations/compound_data/test_expectations_cursor.pks

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,5 +199,17 @@ create or replace package test_expectations_cursor is
199199
--%test( Fail on passing implicit column name as exclude filter )
200200
procedure exclude_col_name_implicit;
201201

202+
--%test( Compare cursors using unordered method success)
203+
procedure cursor_unordered_compare_success;
204+
205+
--%test( Compare cursors using unordered method failure)
206+
procedure cursor_unordered_compare_fail;
207+
208+
--%test( Compare cursors join by single key )
209+
procedure cursor_joinby_compare;
210+
211+
--%test( Compare cursors join by composite key)
212+
procedure cursor_joinby_compare_twocolumns;
213+
202214
end;
203215
/

0 commit comments

Comments
 (0)