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

Skip to content

Commit e082b75

Browse files
committed
Improvements to extraction of cursor details using anydata to allow get into any level of depth ( fix issue with collection object).
Simplify a way the cursor filter is done and check for missing column. Full access path is capture as part of cursor describe. Removal of nft test for over 10k rows.
1 parent 7837eb4 commit e082b75

9 files changed

Lines changed: 224 additions & 197 deletions

source/expectations/data_values/ut_compound_data_helper.pkb

Lines changed: 42 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,6 @@ create or replace package body ut_compound_data_helper is
375375
l_temp_string := ' (a.data_id is null or e.data_id is null) ';
376376
end if;
377377
ut_utils.append_to_clob(l_compare_sql,l_temp_string);
378-
379378
return l_compare_sql;
380379
end;
381380

@@ -402,7 +401,6 @@ create or replace package body ut_compound_data_helper is
402401
l_results tt_row_diffs;
403402
l_sql varchar2(32767);
404403
begin
405-
406404
l_sql := q'[with exp as (
407405
select exp_item_data, exp_data_id, item_no rn,rownum col_no, pk_value,
408406
s.column_value col, s.column_value.getRootElement() col_name, s.column_value.getclobval() col_val
@@ -563,7 +561,7 @@ create or replace package body ut_compound_data_helper is
563561
return dbms_crypto.hash(a_data, a_hash_type);
564562
end;
565563

566-
function get_fixed_size_hash(a_string varchar2, a_base integer :=0,a_size integer :=30) return number is
564+
function get_fixed_size_hash(a_string varchar2, a_base integer :=0,a_size integer := 9999999) return number is
567565
begin
568566
return dbms_utility.get_hash_value(a_string,a_base,a_size);
569567
end;
@@ -595,69 +593,42 @@ create or replace package body ut_compound_data_helper is
595593
return g_diff_count;
596594
end;
597595

598-
function get_cursor_vs_list_sql return varchar2 is
599-
l_sql varchar2(32767) :=
600-
q'[with
601-
sorted as
602-
(select r_num,regexp_substr(t.column_value, '[^/]+', 1, commas.column_value) as colval,commas.column_value lev,
603-
t.column_value access_path
604-
from (select row_number() over(order by 1) r_num, column_value from ((table(:a_current_list)))) t,
605-
table(cast(multiset
606-
(select level from dual connect by level <= length(regexp_replace(t.column_value,'[^/]+')) + 1) as sys.odcinumberlist)) commas
607-
order by r_num,lev),
608-
hier as
609-
(select r_num,lev,colval column_name,lag(colval, 1) over(partition by r_num order by lev) parent_name , access_path
610-
from sorted),
611-
constructed as (
612-
select lev,column_name,parent_name,access_path from hier),
613-
t1(column_name, parent_name) AS (
614-
select column_name,parent_name from table(:a_cursor_info) where parent_name is null
615-
union all
616-
select t2.column_name,t2.parent_name from table(:a_cursor_info) t2, t1 where t2.parent_name = t1.column_name)]';
617-
begin
618-
return l_sql;
619-
end;
620-
596+
--Filter out columns from cursor based on include (exists) or exclude (not exists)
621597
function filter_out_cols(a_cursor_info ut_cursor_column_tab, a_current_list ut_varchar2_list,a_include boolean := true)
622598
return ut_cursor_column_tab is
623-
l_sql varchar2(32767) := get_cursor_vs_list_sql;
624599
l_result ut_cursor_column_tab := ut_cursor_column_tab();
625-
begin
626-
l_sql := l_sql || q'[select ut_cursor_column(i.column_name,i.column_schema,i.column_type_name,i.column_len, i.parent_name,
627-
i.hierarchy_level,i.column_position, i.column_type, i.is_collection)
628-
from t1 join table(:a_cursor_info) i on ( nvl(t1.parent_name,1) = nvl(i.parent_name,1) and t1.column_name = i.column_name)]';
629-
if a_include then
630-
l_sql := l_sql || ' join constructed c on ( nvl(t1.parent_name,1) = nvl(c.parent_name,1) and t1.column_name = c.column_name)';
631-
else
632-
l_sql := l_sql ||' left outer join constructed c on ( nvl(t1.parent_name,1) = nvl(c.parent_name,1) and t1.column_name = c.column_name)
633-
where c.column_name is null';
634-
end if;
635-
636-
execute immediate l_sql bulk collect into l_result
637-
using a_current_list,a_cursor_info,a_cursor_info,a_cursor_info;
600+
l_filter_sql varchar2(32767);
601+
begin
602+
l_filter_sql :=
603+
q'[with
604+
coltab as (
605+
select i.parent_name,i.access_path,i.has_nested_col,i.transformed_name,i.hierarchy_level,i.column_position ,
606+
i.xml_valid_name,i.column_name,i.column_type,i.column_type_name ,i.column_schema,i.column_len,i.is_sql_diffable ,i.is_collection
607+
from table(:cursor_info) i),
608+
filter as (select column_value from table(:current_list))
609+
select ut_cursor_column(i.parent_name,i.access_path,i.has_nested_col,i.transformed_name,i.hierarchy_level,i.column_position ,
610+
i.xml_valid_name,i.column_name,i.column_type,i.column_type_name ,i.column_schema,i.column_len,i.is_sql_diffable ,i.is_collection)
611+
from coltab i where ]'||case when a_include then null else ' not ' end
612+
||q'[exists (select 1 from filter f where regexp_like(i.access_path, '^'||f.column_value||'($|/.*)'))]';
638613

614+
execute immediate l_filter_sql bulk collect into l_result using a_cursor_info,a_current_list;
639615
return l_result;
640616
end;
641-
642-
function compare_cursor_to_columns(a_cursor_info ut_cursor_column_tab, a_current_list ut_varchar2_list)
643-
return ut_varchar2_list is
644-
l_sql varchar2(32767) := get_cursor_vs_list_sql;
617+
618+
function get_missing_filter_columns(a_cursor_info ut_cursor_column_tab, a_column_filter_list ut_varchar2_list) return ut_varchar2_list is
645619
l_result ut_varchar2_list := ut_varchar2_list();
646-
begin
647-
l_sql := l_sql || q'[select c.access_path
648-
from t1 join table(:a_cursor_info) i on ( nvl(t1.parent_name,1) = nvl(i.parent_name,1) and t1.column_name = i.column_name)]';
649-
l_sql := l_sql ||'right outer join constructed c on ( nvl(t1.parent_name,1) = nvl(c.parent_name,1) and t1.column_name = c.column_name)
650-
where t1.column_name is null';
651-
652-
execute immediate l_sql bulk collect into l_result
653-
using a_current_list,a_cursor_info,a_cursor_info,a_cursor_info;
654-
return l_result;
620+
begin
621+
select fl.column_value
622+
bulk collect into l_result
623+
from table(a_column_filter_list) fl
624+
where not exists (select 1 from table(a_cursor_info) c where regexp_like(c.access_path, '^'||fl.column_value||'($|/.*)'));
625+
return l_result;
655626
end;
656-
627+
657628
function get_missing_pk(a_expected ut_cursor_column_tab, a_actual ut_cursor_column_tab, a_current_list ut_varchar2_list)
658629
return tt_missing_pk is
659-
l_actual ut_varchar2_list := coalesce(compare_cursor_to_columns(a_actual,a_current_list),ut_varchar2_list());
660-
l_expected ut_varchar2_list := coalesce(compare_cursor_to_columns(a_expected,a_current_list),ut_varchar2_list());
630+
l_actual ut_varchar2_list := coalesce(get_missing_filter_columns(a_actual,a_current_list),ut_varchar2_list());
631+
l_expected ut_varchar2_list := coalesce(get_missing_filter_columns(a_expected,a_current_list),ut_varchar2_list());
661632
l_missing_pk tt_missing_pk;
662633
begin
663634
select name,type
@@ -735,14 +706,14 @@ create or replace package body ut_compound_data_helper is
735706
function remove_incomparable_cols( a_cursor_details ut_cursor_column_tab,a_incomparable_cols ut_varchar2_list) return ut_cursor_column_tab is
736707
l_result ut_cursor_column_tab;
737708
begin
738-
select ut_cursor_column(i.column_name,i.column_schema,i.column_type_name,i.column_len, i.parent_name,
739-
i.hierarchy_level,i.column_position, i.column_type, i.is_collection)
709+
select ut_cursor_column(i.parent_name,i.access_path,i.has_nested_col,i.transformed_name,i.hierarchy_level,i.column_position ,
710+
i.xml_valid_name,i.column_name,i.column_type,i.column_type_name ,i.column_schema,i.column_len,i.is_sql_diffable ,i.is_collection)
740711
bulk collect into l_result
741712
from table(a_cursor_details) i
742713
left outer join table(a_incomparable_cols) c
743714
on (i.access_path = c.column_value)
744715
where c.column_value is null;
745-
716+
746717
return l_result;
747718
end;
748719

@@ -759,13 +730,12 @@ create or replace package body ut_compound_data_helper is
759730
return xmltype is
760731
l_result xmltype;
761732
begin
762-
763733
select xmlagg(xmlelement(evalname t.column_name,t.column_type,
764734
getxmlchildren(t.column_name,a_cursor_table)))
765735
into l_result
766736
from table(a_cursor_table) t
767-
where (a_parent_name is not null and parent_name = a_parent_name)
768-
or (a_parent_name is null and parent_name is null)
737+
where (a_parent_name is not null and parent_name = a_parent_name and hierarchy_level > 1 and column_name is not null)
738+
or (a_parent_name is null and parent_name is null and hierarchy_level = 1 and column_name is not null)
769739
having count(*) > 0;
770740

771741

@@ -805,6 +775,14 @@ create or replace package body ut_compound_data_helper is
805775
return false;
806776
end;
807777

778+
function is_collection (a_anytype_code in integer) return boolean is
779+
l_type_view varchar2(200) := ut_metadata.get_dba_view('dba_types');
780+
l_typecode varchar2(100);
781+
begin
782+
return a_anytype_code in (dbms_types.typecode_varray,dbms_types.typecode_table,dbms_types.typecode_namedcollection);
783+
end;
784+
785+
--TODO Look at simplify that option
808786
function get_column_type_desc(a_type_code in integer, a_dbms_sql_desc in boolean) return varchar2 is
809787
begin
810788
return case when a_dbms_sql_desc then g_type_name_map(a_type_code) else g_anytype_name_map(a_type_code) end;
@@ -832,7 +810,8 @@ begin
832810
g_anytype_name_map(dbms_types.typecode_varray) := 'VARRRAY';
833811
g_anytype_name_map(dbms_types.typecode_table) := 'TABLE';
834812
g_anytype_name_map(dbms_types.typecode_namedcollection) := 'NAMEDCOLLECTION';
835-
813+
g_anytype_name_map(dbms_types.typecode_object) := 'OBJECT';
814+
836815
g_type_name_map( dbms_sql.binary_bouble_type ) := 'BINARY_DOUBLE';
837816
g_type_name_map( dbms_sql.bfile_type ) := 'BFILE';
838817
g_type_name_map( dbms_sql.binary_float_type ) := 'BINARY_FLOAT';

source/expectations/data_values/ut_compound_data_helper.pks

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ create or replace package ut_compound_data_helper authid definer is
8383
function get_hash(a_data raw, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash;
8484
function get_hash(a_data clob, a_hash_type binary_integer := dbms_crypto.hash_sh1) return t_hash;
8585

86-
function get_fixed_size_hash(a_string varchar2, a_base integer :=0,a_size integer :=30) return number;
86+
function get_fixed_size_hash(a_string varchar2, a_base integer :=0,a_size integer :=9999999) return number;
8787

8888
function gen_compare_sql(a_inclusion_type boolean, a_is_negated boolean, a_unordered boolean,
8989
a_other ut_data_value_refcursor :=null, a_join_by_list ut_varchar2_list:=ut_varchar2_list() ) return clob;
@@ -99,9 +99,6 @@ create or replace package ut_compound_data_helper authid definer is
9999
function filter_out_cols(a_cursor_info ut_cursor_column_tab, a_current_list ut_varchar2_list,a_include boolean := true)
100100
return ut_cursor_column_tab;
101101

102-
function compare_cursor_to_columns(a_cursor_info ut_cursor_column_tab, a_current_list ut_varchar2_list)
103-
return ut_varchar2_list;
104-
105102
function get_missing_pk(a_expected ut_cursor_column_tab, a_actual ut_cursor_column_tab, a_current_list ut_varchar2_list)
106103
return tt_missing_pk;
107104

@@ -122,6 +119,8 @@ create or replace package ut_compound_data_helper authid definer is
122119

123120
function is_collection (a_owner varchar2,a_type_name varchar2, a_anytype_code in integer :=null) return boolean;
124121

122+
function is_collection (a_anytype_code in integer) return boolean;
123+
125124
function get_column_type_desc(a_type_code in integer, a_dbms_sql_desc in boolean) return varchar2;
126125

127126
end;

source/expectations/data_values/ut_cursor_column.tpb

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,49 @@ create or replace type body ut_cursor_column as
33
member procedure init(self in out nocopy ut_cursor_column,
44
a_col_name varchar2, a_col_schema_name varchar2,
55
a_col_type_name varchar2, a_col_max_len integer, a_parent_name varchar2 := null, a_hierarchy_level integer := 1,
6-
a_col_position integer, a_col_type varchar2, a_collection integer) is
6+
a_col_position integer, a_col_type varchar2, a_collection integer,a_access_path in varchar2) is
77
begin
8-
self.parent_name := a_parent_name;
9-
self.hierarchy_level := a_hierarchy_level;
10-
self.column_position := a_col_position;
11-
self.column_len := a_col_max_len;
12-
self.column_name := TRIM( BOTH '''' FROM a_col_name);
13-
self.column_type_name := a_col_type_name;
14-
self.access_path := case when self.parent_name is null then self.column_name else self.parent_name||'/'||self.column_name end;
15-
self.xml_valid_name := '"'||self.column_name||'"';
8+
self.parent_name := a_parent_name; --Name of the parent if its nested
9+
self.hierarchy_level := a_hierarchy_level; --Hierarchy level
10+
self.column_position := a_col_position; --Position of the column in cursor/ type
11+
self.column_len := a_col_max_len; --length of column
12+
self.column_name := TRIM( BOTH '''' FROM a_col_name); --name of the column
13+
self.column_type_name := a_col_type_name; --type name e.g. test_dummy_object or varchar2
14+
self.access_path := case when a_access_path is null then
15+
self.column_name
16+
else
17+
a_access_path||'/'||self.column_name
18+
end; --Access path used for incldue exclude eg/ TEST_DUMMY_OBJECT/VARCHAR2
19+
self.xml_valid_name := '"'||self.column_name||'"'; --User friendly column name
1620
self.transformed_name := case when self.parent_name is null then
1721
self.xml_valid_name
1822
else
1923
'"'||ut_compound_data_helper.get_fixed_size_hash(self.parent_name||self.column_name)||'"'
20-
end;
21-
self.column_type := a_col_type;
22-
self.column_schema := a_col_schema_name;
24+
end; --when is nestd we need to hash name to make sure we dont exceed 30 char
25+
self.column_type := a_col_type; --column type e.g. user_defined , varchar2
26+
self.column_schema := a_col_schema_name; -- schema name
2327
self.is_sql_diffable := case when lower(self.column_type) = 'user_defined_type' then
2428
0
2529
else
2630
ut_utils.boolean_to_int(ut_compound_data_helper.is_sql_compare_allowed(self.column_type))
27-
end;
28-
--TODO : Part of the constructor same as has nested ??
31+
end; --can we directly compare or do we need to hash value
2932
self.is_collection := a_collection;
3033
--TODO : fix that as is nasty hardcode
3134
self.has_nested_col := case when lower(self.column_type) = 'user_defined_type' and self.is_collection = 0 then 1 else 0 end;
3235
end;
33-
34-
--TODO : Scenarios :
35-
--namedcollection xmltype getclobhash
36-
--collection xml type get clob hash
37-
-- user defined type
38-
36+
3937
constructor function ut_cursor_column( self in out nocopy ut_cursor_column,
4038
a_col_name varchar2, a_col_schema_name varchar2,
4139
a_col_type_name varchar2, a_col_max_len integer, a_parent_name varchar2 := null, a_hierarchy_level integer := 1,
42-
a_col_position integer, a_col_type in varchar2, a_collection integer) return self as result is
40+
a_col_position integer, a_col_type in varchar2, a_collection integer,a_access_path in varchar2) return self as result is
4341
begin
44-
init(a_col_name, a_col_schema_name, a_col_type_name, a_col_max_len, a_parent_name,a_hierarchy_level, a_col_position, a_col_type, a_collection);
42+
init(a_col_name, a_col_schema_name, a_col_type_name, a_col_max_len, a_parent_name,a_hierarchy_level, a_col_position, a_col_type, a_collection,a_access_path);
4543
return;
4644
end;
45+
46+
constructor function ut_cursor_column( self in out nocopy ut_cursor_column) return self as result is
47+
begin
48+
return;
49+
end;
4750
end;
4851
/

source/expectations/data_values/ut_cursor_column.tps

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ create or replace type ut_cursor_column force authid current_user as object
1818
member procedure init(self in out nocopy ut_cursor_column,
1919
a_col_name varchar2, a_col_schema_name varchar2,
2020
a_col_type_name varchar2, a_col_max_len integer, a_parent_name varchar2 := null, a_hierarchy_level integer := 1,
21-
a_col_position integer, a_col_type in varchar2, a_collection integer),
21+
a_col_position integer, a_col_type in varchar2, a_collection integer,a_access_path in varchar2),
2222

2323
constructor function ut_cursor_column( self in out nocopy ut_cursor_column,
2424
a_col_name varchar2, a_col_schema_name varchar2,
2525
a_col_type_name varchar2, a_col_max_len integer, a_parent_name varchar2 := null, a_hierarchy_level integer := 1,
26-
a_col_position integer, a_col_type in varchar2, a_collection integer)
27-
return self as result
26+
a_col_position integer, a_col_type in varchar2, a_collection integer,a_access_path in varchar2)
27+
return self as result,
28+
29+
constructor function ut_cursor_column( self in out nocopy ut_cursor_column) return self as result
2830
)
2931
/

0 commit comments

Comments
 (0)