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

Skip to content

Commit ab593d9

Browse files
committed
Update code to consolidate compare sqls into one place where is generated dynamically
1 parent 9843e14 commit ab593d9

9 files changed

Lines changed: 122 additions & 228 deletions

source/expectations/data_values/ut_compound_data_helper.pkb

Lines changed: 74 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,15 @@ create or replace package body ut_compound_data_helper is
2525
l_data ut_data_value := a_column_details.value;
2626
l_key varchar2(4000) := ut_utils.xmlgen_escaped_string(a_column_details.KEY);
2727
l_is_diff number;
28-
begin
28+
begin
2929
l_result := '<'||l_key||' xml_valid_name="'||l_key;
3030
if l_data is of(ut_data_value_xmltype) then
31-
l_result := l_result||'" sql_diffable="0">' || (treat(l_data as ut_data_value_xmltype).to_string);
31+
l_result := l_result||'" sql_diffable="0" user_defined="1" >' ||trim( both '''' from (treat(l_data as ut_data_value_xmltype).to_string));
3232
else
3333
l_is_diff := ut_curr_usr_compound_helper.is_sql_compare_int((treat(l_data as ut_data_value_varchar2).data_value));
34-
l_result := l_result||'" sql_diffable="'||l_is_diff||'">' || ut_utils.xmlgen_escaped_string((treat(l_data as ut_data_value_varchar2).data_value));
34+
l_result := l_result||'" sql_diffable="'||l_is_diff||'" user_defined="0">' || ut_utils.xmlgen_escaped_string((treat(l_data as ut_data_value_varchar2).data_value));
3535
end if;
36-
37-
l_result := l_result ||'</'||l_key||'>';
36+
l_result := l_result ||'</'||l_key||'>';
3837
return xmltype(l_result);
3938
end;
4039

@@ -202,6 +201,8 @@ create or replace package body ut_compound_data_helper is
202201
from diff_info i,
203202
table( xmlsequence( extract(i.act_item_data,'/*/*') ) ) s
204203
where i.act_data_id = :other_guid)
204+
select rn, diff_type, diffed_row, pk_value pk_value
205+
from (
205206
select rn, diff_type, xmlserialize(content data_item no indent) diffed_row, pk_value pk_value
206207
from (
207208
select nvl(exp.rn, act.rn) rn, nvl(exp.pk_value, act.pk_value) pk_value, exp.col exp_item, act.col act_item
@@ -215,7 +216,8 @@ create or replace package body ut_compound_data_helper is
215216
nvl2(i.join_by,ut3.ut_compound_data_helper.get_pk_value(i.join_by,case when exp_data_id is null then act_item_data else exp_item_data end),null) pk_value
216217
from diff_info i
217218
where act_data_id is null or exp_data_id is null
218-
order by 1 , 2]'
219+
)
220+
order by 2, 1]'
219221
bulk collect into l_results
220222
using a_exclude_xpath,a_include_xpath,
221223
a_exclude_xpath,a_include_xpath,
@@ -359,7 +361,7 @@ create or replace package body ut_compound_data_helper is
359361
if a_join_by_xpath is not null then
360362
l_pk_xpath_tabs := ut_utils.string_to_table(a_join_by_xpath,'|');
361363
l_column_filter := get_columns_row_filter(a_exclude_xpath, a_include_xpath);
362-
364+
363365
execute immediate q'[
364366
with xpaths_tab as (select column_value xpath from table(:xpath_tabs)),
365367
expected_column_info as ( select :expected as item_data from dual ),
@@ -390,84 +392,7 @@ create or replace package body ut_compound_data_helper is
390392

391393
return l_no_missing_keys;
392394
end;
393-
394-
function get_inclusion_matcher_sql(a_owner in varchar2) return varchar2 is
395-
l_sql varchar2(32767);
396-
begin
397-
l_sql := 'with source_data as
398-
( select t.data_id,t.item_hash,t.duplicate_no,
399-
pk_hash
400-
from ' || a_owner || '.ut_compound_data_tmp t
401-
where data_id = :self_guid or data_id = :other_guid
402-
)
403-
select distinct :diff_id,tmp.item_hash,tmp.pk_hash,tmp.duplicate_no
404-
from(
405-
(
406-
select t.item_hash,t. duplicate_no,t.pk_hash
407-
from source_data t
408-
where t.data_id = :self_guid
409-
minus
410-
select t.item_hash,t. duplicate_no,t.pk_hash
411-
from source_data t
412-
where t.data_id = :other_guid
413-
)
414-
union all
415-
(
416-
select t.item_hash,t. duplicate_no,t.pk_hash
417-
from source_data t,
418-
source_data s
419-
where t.data_id = :other_guid
420-
and s.data_id = :self_guid
421-
and t.pk_hash = s.pk_hash
422-
and t.item_hash != s.item_hash
423-
)
424-
)
425-
tmp';
426-
return l_sql;
427-
end;
428-
429-
function get_not_inclusion_matcher_sql(a_owner in varchar2) return varchar2 is
430-
l_sql varchar2(32767);
431-
begin
432-
/* Self set does not contain any values from other set */
433-
l_sql := 'with source_data as
434-
( select t.data_id,t.item_hash,t.duplicate_no,
435-
pk_hash
436-
from ' || a_owner || '.ut_compound_data_tmp t
437-
where data_id = :self_guid or data_id = :other_guid
438-
)
439-
select distinct :diff_id,tmp.item_hash,tmp.pk_hash,tmp.duplicate_no
440-
from
441-
(
442-
select act.item_hash,act. duplicate_no,act.pk_hash
443-
from source_data act where act.data_id = :self_guid
444-
and exists ( select 1
445-
from source_data exp
446-
where exp.data_id = :other_guid
447-
and exp.item_hash = act.item_hash
448-
)
449-
union all
450-
select null,null,null
451-
from dual where :other_guid = :self_guid
452-
)
453-
tmp';
454-
return l_sql;
455-
end;
456-
457-
-- TODO:Rebuild as the unordered can be done using join_by compare
458-
function get_refcursor_matcher_sql(a_owner in varchar2,a_inclusion_matcher boolean := false, a_negated_match boolean := false) return varchar2 is
459-
l_sql varchar2(32767);
460-
begin
461-
l_sql := 'insert into ' || a_owner || '.ut_compound_data_diff_tmp ( diff_id,item_hash,pk_hash,duplicate_no)'||chr(10);
462-
if a_inclusion_matcher and not(a_negated_match) then
463-
l_sql := l_sql || get_inclusion_matcher_sql(a_owner);
464-
elsif a_inclusion_matcher and a_negated_match then
465-
l_sql := l_sql || get_not_inclusion_matcher_sql(a_owner);
466-
end if;
467-
468-
return l_sql;
469-
end;
470-
395+
471396
function generate_select_stmt(a_column_info ut_varchar2_list,a_xml_column_info xmltype) return clob is
472397
l_sql_stmt clob;
473398
l_col_type varchar2(4000);
@@ -570,19 +495,41 @@ create or replace package body ut_compound_data_helper is
570495
for i in 1..a_column_info.count loop
571496
l_sql_stmt := l_sql_stmt || case when l_sql_stmt is null then null else ' and ' end ||' a.'||a_column_info(i)||q'[ = ]'||' e.'||a_column_info(i);
572497
end loop;
573-
574498
return l_sql_stmt;
575499
end;
576500

577-
function generate_join_by_on_stmt (a_join_by_xpath_tab ut_varchar2_list) return clob is
501+
function generate_join_by_on_stmt (a_join_by_xpath_tab ut_varchar2_list, a_columns_info xmltype, a_join_by_xpath in varchar2) return clob is
578502
l_sql_stmt clob;
579-
begin
580-
for i in (with xpaths_tab as (select column_value xpath from table(a_join_by_xpath_tab))
581-
select REGEXP_SUBSTR (xpath,'[^(/\*/)](.+)$') name
582-
from xpaths_tab)
503+
l_non_diff_var varchar2(32767);
504+
l_ut_owner varchar2(250) := ut_utils.ut_owner;
505+
begin
506+
for i in (select /*+ CARDINALITY(xt 100) */
507+
distinct
508+
t.column_value,
509+
xt.is_sql_diff
510+
from
511+
(select a_columns_info item_data from dual) x,
512+
xmltable(
513+
'/ROW/*'
514+
passing x.item_data
515+
columns
516+
name varchar2(4000) PATH '@xml_valid_name',
517+
is_sql_diff varchar2(4000) PATH '@sql_diffable'
518+
) xt,
519+
table(a_join_by_xpath_tab) t
520+
where xt.name = t.column_value)
583521
loop
584-
l_sql_stmt := l_sql_stmt || case when l_sql_stmt is null then null else ' and ' end ||' a.'||i.name||q'[ = ]'||' e.'||i.name;
522+
523+
if i.is_sql_diff = 0 then
524+
l_non_diff_var := l_ut_owner ||'.ut_compound_data_helper.get_hash((extract( a.'||i.column_value||','||a_join_by_xpath||')).getclobval()) = '
525+
||l_ut_owner ||'.ut_compound_data_helper.get_hash((extract( e.'||i.column_value||','||a_join_by_xpath||')).getclobval())';
526+
l_sql_stmt := l_sql_stmt || case when l_sql_stmt is null then null else ' and ' end ||' a.'||i.column_value||q'[ = ]'||' e.'||i.column_value;
527+
elsif i.is_sql_diff = 1 then
528+
l_sql_stmt := l_sql_stmt || case when l_sql_stmt is null then null else ' and ' end ||' a.'||i.column_value||q'[ = ]'||' e.'||i.column_value;
529+
end if;
530+
585531
end loop;
532+
586533
return l_sql_stmt;
587534
end;
588535

@@ -605,7 +552,7 @@ create or replace package body ut_compound_data_helper is
605552
end;
606553

607554
function gen_compare_sql(a_column_info xmltype, a_exclude_xpath varchar2,
608-
a_include_xpath varchar2, a_join_by_xpath varchar2) return clob is
555+
a_include_xpath varchar2, a_join_by_xpath varchar2, a_inclusion_type boolean, a_is_negated boolean ) return clob is
609556
l_compare_sql clob;
610557
l_temp_string varchar2(32767);
611558

@@ -621,7 +568,7 @@ create or replace package body ut_compound_data_helper is
621568
function get_columns_names (a_xpath_tab in ut_varchar2_list) return ut_varchar2_list is
622569
l_names_tab ut_varchar2_list := ut_varchar2_list();
623570
begin
624-
select distinct REGEXP_SUBSTR (column_value,'[^(/\*/)](.+)$')
571+
select distinct REGEXP_SUBSTR (column_value,'[^(\/*\/)]+',1,1)
625572
bulk collect into l_names_tab
626573
from table(a_xpath_tab);
627574
return l_names_tab;
@@ -642,12 +589,23 @@ create or replace package body ut_compound_data_helper is
642589
) xt;
643590
return l_columns_info;
644591
end;
645-
592+
593+
function get_join_type(a_inclusion_compare in boolean,a_negated in boolean) return varchar2 is
594+
begin
595+
if a_inclusion_compare and not(a_negated) then
596+
return ' right outer join ';
597+
elsif a_inclusion_compare and a_negated then
598+
return ' inner join ';
599+
else
600+
return ' full outer join ';
601+
end if;
602+
end;
603+
646604
begin
647605
dbms_lob.createtemporary(l_compare_sql, true);
648606

607+
--TODO: Resolve issues with collection and nested tables, can we extract by internal column name if defined e.g. xml of colval.id.getclobval()
649608
--Check include and exclude columns and create an actual column list that have to be compared.
650-
--TODO :Reformat
651609
if a_include_xpath is null and a_exclude_xpath is null then
652610
l_act_col_tab := get_columns_info(a_column_info);
653611
elsif a_include_xpath is not null and a_exclude_xpath is null then
@@ -697,28 +655,34 @@ create or replace package body ut_compound_data_helper is
697655
-- If no key defined do the join on all columns
698656
l_temp_string := ' select a.item_data as act_item_data, a.data_id act_data_id,'
699657
||'e.item_data as exp_item_data, e.data_id exp_data_id, rownum item_no, nvl(e.dup_no,a.dup_no) dup_no '
700-
||'from act a full outer join exp e on ( ';
658+
||'from act a '||get_join_type(a_inclusion_type,a_is_negated)||' exp e on ( ';
701659
ut_utils.append_to_clob(l_compare_sql,l_temp_string);
702-
ut_utils.append_to_clob(l_compare_sql,generate_equal_sql(l_act_col_tab)||q'[ and e.dup_no = a.dup_no ) where a.data_id is null or e.data_id is null]');
660+
ut_utils.append_to_clob(l_compare_sql,generate_equal_sql(l_act_col_tab)||q'[ and e.dup_no = a.dup_no ) where ]');
703661
else
704662
-- If key defined do the join or these and where on diffrences
705663
l_temp_string := q'[ select a.item_data act_item_data, a.data_id act_data_id, ]'
706-
||' e.item_data exp_item_data, e.data_id exp_data_id, rownum item_no,nvl(e.dup_no,a.dup_no) dup_no from act a full outer join exp e on ( e.dup_no = a.dup_no and ';
664+
||' e.item_data exp_item_data, e.data_id exp_data_id, rownum item_no,nvl(e.dup_no,a.dup_no) dup_no from act a '||get_join_type(a_inclusion_type,a_is_negated)||' exp e on ( e.dup_no = a.dup_no and ';
707665
ut_utils.append_to_clob(l_compare_sql,l_temp_string);
708666

709-
ut_utils.append_to_clob(l_compare_sql,generate_join_by_on_stmt (l_pk_xpath_tabs)||' ) ');
667+
ut_utils.append_to_clob(l_compare_sql,generate_join_by_on_stmt (l_pk_xpath_tabs,a_column_info,a_join_by_xpath)||' ) where');
710668

711-
l_where_stmt := generate_not_equal_sql(l_act_col_tab, l_pk_xpath_tabs);
712-
case
713-
when l_where_stmt is null then
714-
ut_utils.append_to_clob(l_compare_sql,' where a.data_id is null or e.data_id is null');
715-
else
716-
ut_utils.append_to_clob(l_compare_sql,' where ( '||l_where_stmt||' ) or ( a.data_id is null or e.data_id is null )');
717-
end case;
669+
670+
if not a_is_negated then
671+
l_where_stmt := generate_not_equal_sql(l_act_col_tab, l_pk_xpath_tabs);
672+
if l_where_stmt is not null then
673+
ut_utils.append_to_clob(l_compare_sql,' ( '||l_where_stmt||' ) or ');
674+
end if;
675+
end if;
718676
end if;
719-
720-
--TEST
721-
dbms_output.put_line( l_compare_sql);
677+
678+
--If its inlcusion we expect a actual set to fully match and have no extra elements over expected
679+
if a_inclusion_type and not(a_is_negated) then
680+
l_temp_string := ' ( a.data_id is null ) ';
681+
else
682+
l_temp_string := ' (a.data_id is null or e.data_id is null) ';
683+
end if;
684+
ut_utils.append_to_clob(l_compare_sql,l_temp_string);
685+
722686
return l_compare_sql;
723687
end;
724688

source/expectations/data_values/ut_compound_data_helper.pks

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,9 @@ create or replace package ut_compound_data_helper authid definer is
8888

8989
function is_pk_exists(a_expected_cursor xmltype, a_actual_cursor xmltype, a_exclude_xpath varchar2, a_include_xpath varchar2,a_join_by_xpath varchar2)
9090
return tt_missing_pk;
91-
92-
function get_refcursor_matcher_sql(a_owner in varchar2,a_inclusion_matcher boolean := false, a_negated_match boolean := false) return varchar2;
93-
91+
9492
function gen_compare_sql(a_column_info xmltype, a_exclude_xpath varchar2,
95-
a_include_xpath varchar2, a_join_by_xpath varchar2) return clob;
93+
a_include_xpath varchar2, a_join_by_xpath varchar2, a_inclusion_type boolean, a_is_negated boolean ) return clob;
9694

9795
procedure insert_diffs_result(a_diff_tab t_diff_tab, a_diff_id raw);
9896

source/expectations/data_values/ut_compound_data_value.tpb

Lines changed: 8 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -234,58 +234,10 @@ create or replace type body ut_compound_data_value as
234234
return l_result;
235235
end;
236236

237-
member function compare_implementation(a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2,
238-
a_unordered boolean , a_inclusion_compare boolean := false, a_is_negated boolean := false ) return integer is
239-
l_other ut_compound_data_value;
240-
l_ut_owner varchar2(250) := ut_utils.ut_owner;
241-
l_diff_id ut_compound_data_helper.t_hash;
242-
l_result integer;
243-
l_row_diffs ut_compound_data_helper.tt_row_diffs;
244-
c_max_rows constant integer := 20;
245-
l_sql varchar2(32767);
246-
247-
begin
248-
if not a_other is of (ut_compound_data_value) then
249-
raise value_error;
250-
end if;
251-
252-
l_other := treat(a_other as ut_compound_data_value);
253-
254-
l_diff_id := ut_compound_data_helper.get_hash(self.data_id||l_other.data_id);
255-
256-
/*!*
257-
* Comparision is based on type of search, for inclusion based search we will look for left join only.
258-
* For normal two side diff we will peform minus on two sets two get diffrences.
259-
* SELF is expected.
260-
* Due to growing complexity I have moved a dynamic SQL into helper package.
261-
*/
262-
l_sql := ut_compound_data_helper.get_refcursor_matcher_sql(l_ut_owner,a_inclusion_compare,a_is_negated);
237+
member function compare_implementation(a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2,
238+
a_join_by_xpath varchar2,a_unordered boolean, a_inclusion_compare boolean := false, a_is_negated boolean := false ) return integer is
263239

264-
execute immediate l_sql
265-
using self.data_id, l_other.data_id,
266-
l_diff_id,
267-
self.data_id, l_other.data_id,
268-
l_other.data_id,self.data_id;
269-
270-
/*!*
271-
* Result OK when is not inclusion matcher and both are the same
272-
* Resullt OK when is inclusion matcher and left contains right set
273-
*/
274-
if sql%rowcount = 0 and self.elements_count = l_other.elements_count and not(a_inclusion_compare ) then
275-
l_result := 0;
276-
elsif sql%rowcount = 0 and a_inclusion_compare then
277-
l_result := 0;
278-
else
279-
l_result := 1;
280-
end if;
281-
return l_result;
282-
end;
283-
284-
member function compare_implementation_by_sql(a_other ut_data_value, a_exclude_xpath varchar2, a_include_xpath varchar2, a_join_by_xpath varchar2, a_inclusion_compare boolean := false) return integer is
285-
286-
l_actual ut_data_value_refcursor := treat(a_other as ut_data_value_refcursor);
287-
l_diff_id ut_compound_data_helper.t_hash;
288-
240+
l_diff_id ut_compound_data_helper.t_hash;
289241
l_other ut_compound_data_value;
290242
l_result integer;
291243
--We will start with number od differences being displayed.
@@ -299,16 +251,16 @@ create or replace type body ut_compound_data_value as
299251
--TODO : Error on xml when same column is more then once in item data xml.Do we need to cleanup ??
300252
l_other := treat(a_other as ut_compound_data_value);
301253
l_diff_id := ut_compound_data_helper.get_hash(self.data_id||l_other.data_id);
302-
303-
open l_loop_curs for ut_compound_data_helper.gen_compare_sql(l_actual.columns_info, a_exclude_xpath,
304-
a_include_xpath, a_join_by_xpath) using self.data_id,l_actual.data_id;
254+
255+
open l_loop_curs for ut_compound_data_helper.gen_compare_sql(treat(a_other as ut_data_value_refcursor).columns_info, a_exclude_xpath,
256+
a_include_xpath, a_join_by_xpath, a_inclusion_compare, a_is_negated) using self.data_id,l_other.data_id;
305257
loop
306258
fetch l_loop_curs bulk collect into l_diff_tab limit l_max_rows;
307259
exit when l_diff_tab.count = 0;
308260
if (ut_utils.gc_diff_max_rows > l_sql_rowcount ) then
309261
ut_compound_data_helper.insert_diffs_result(l_diff_tab,l_diff_id);
310262
end if;
311-
263+
312264
l_sql_rowcount := l_sql_rowcount + l_diff_tab.count;
313265

314266
if (ut_utils.gc_diff_max_rows <= l_sql_rowcount and l_max_rows != ut_utils.gc_bc_fetch_limit ) then
@@ -318,7 +270,7 @@ create or replace type body ut_compound_data_value as
318270

319271
ut_compound_data_helper.set_rows_diff(l_sql_rowcount);
320272
--result is OK only if both are same
321-
if l_sql_rowcount = 0 and self.elements_count = l_other.elements_count then
273+
if l_sql_rowcount = 0 and ( self.elements_count = l_other.elements_count or a_inclusion_compare )then
322274
l_result := 0;
323275
else
324276
l_result := 1;

0 commit comments

Comments
 (0)