@@ -18,6 +18,7 @@ create or replace package body ut_compound_data_helper is
1818
1919 g_user_defined_type pls_integer := dbms_sql.user_defined_type;
2020 g_diff_count integer;
21+ g_filter_tab ut_varchar2_list;
2122
2223 function get_column_info_xml(a_column_details ut_key_anyval_pair) return xmltype is
2324 l_result varchar2(4000);
@@ -620,7 +621,7 @@ create or replace package body ut_compound_data_helper is
620621
621622 begin
622623 dbms_lob.createtemporary(l_compare_sql, true);
623-
624+
624625 --TODO: Resolve issues with collection and nested tables, can we extract by internal column name if defined e.g. xml of colval.id.getclobval()
625626 --TODO: Comment better all pieces
626627 l_column_filter := get_columns_row_filter(a_exclude_xpath, a_include_xpath);
@@ -717,7 +718,7 @@ create or replace package body ut_compound_data_helper is
717718 l_temp_string := ' (a.data_id is null or e.data_id is null) ';
718719 end if;
719720 ut_utils.append_to_clob(l_compare_sql,l_temp_string);
720-
721+
721722 return l_compare_sql;
722723 end;
723724
@@ -748,5 +749,129 @@ create or replace package body ut_compound_data_helper is
748749 return g_diff_count;
749750 end;
750751
751- end;
752+ function populate_filter_columns (a_column_string in varchar2, a_column_info ut_column_info_tab) return ut_column_info_rec is
753+ l_result ut_column_info_rec;
754+ l_column_from_string varchar2(32767);
755+ l_rest_of_path varchar2(32767);
756+ begin
757+ --check if string has a path
758+ l_column_from_string := regexp_substr(a_column_string,'^([^\/]*)?\/?(.*)',1,1,null,1);
759+ for col in 1..a_column_info.count loop
760+ if l_column_from_string = a_column_info(col).column_name then
761+ if a_column_string like '%/%' then
762+ l_rest_of_path := regexp_substr(a_column_string,'^([^\/]*)?\/(.*)',1,1,null,2);
763+ l_result := treat(a_column_info(col) as ut_column_info_rec);
764+ l_result.nested_details := ut_column_info_tab();
765+ l_result.nested_details.extend;
766+ l_result.nested_details(l_result.nested_details.last) := populate_filter_columns (l_rest_of_path,treat(a_column_info(col) as ut_column_info_rec).nested_details);
767+ else
768+ l_result := treat(a_column_info(col) as ut_column_info_rec);
769+ end if;
770+ end if;
771+ end loop;
772+ return l_result;
773+ end;
774+
775+ function get_child(a_parent in varchar2 default null) return ut_varchar2_list is
776+ l_out_tab ut_varchar2_list := ut_varchar2_list();
777+ cursor c_child(cp_parent in varchar2) is
778+ with sorted as
779+ (select r_num,
780+ regexp_substr(t.column_value, '[^/]+', 1, commas.column_value) as colval,
781+ commas.column_value lev
782+ from (select row_number() over(order by 1) r_num,
783+ column_value
784+ from ((table(g_filter_tab)))) t,
785+ table(cast(multiset
786+ (select level
787+ from dual
788+ connect by level <=
789+ length(regexp_replace(t.column_value,
790+ '[^/]+')) + 1) as
791+ sys.odcinumberlist)) commas
792+ order by r_num,
793+ lev),
794+ hier as
795+ (select r_num,
796+ lev,
797+ colval,
798+ lag(colval, 1) over(partition by r_num order by lev) parent
799+ from sorted)
800+ select distinct colval
801+ from hier
802+ where nvl(parent, 1) = nvl(cp_parent, 1);
803+
804+ begin
805+ open c_child(a_parent);
806+ fetch c_child bulk collect
807+ into l_out_tab;
808+ close c_child;
809+ return l_out_tab;
810+ end;
811+
812+ function exc_inc_cursors_columns(a_column_info_tab ut_column_info_tab,a_current_list ut_varchar2_list)
813+ return ut_column_info_tab is
814+ l_result ut_column_info_tab := ut_column_info_tab();
815+ l_record ut_column_info_rec;
816+ l_index integer := 1;
817+ begin
818+ --TODO : Optimize search using while or exists operator ?
819+ for lst in 1..a_current_list.count loop
820+ for i in 1..a_column_info_tab.count loop
821+ if a_current_list(lst) = a_column_info_tab(i).column_name then
822+ l_result.extend;
823+ if a_column_info_tab(i) is of (ut_column_info_rec) then
824+ l_record := treat(a_column_info_tab(i) as ut_column_info_rec);
825+ l_record.nested_details := exc_inc_cursors_columns(treat(a_column_info_tab(i) as ut_column_info_rec).nested_details,get_child(a_column_info_tab(i).column_name));
826+ end if;
827+ l_result(l_result.last) := l_record;
828+ end if;
829+ end loop;
830+ end loop;
831+ return l_result;
832+ end;
833+
834+ function inc_exc_columns_from_cursor (a_cursor_info ut_column_info_tab, a_exclude_xpath ut_varchar2_list, a_include_xpath ut_varchar2_list)
835+ return ut_column_info_tab is
836+ l_filtered_set ut_varchar2_list := ut_varchar2_list();
837+ l_result ut_column_info_tab := ut_column_info_tab();
838+ begin
839+ g_filter_tab := ut_varchar2_list();
840+
841+ -- if include and exclude is not null its columns from include minus exclude
842+ -- If inlcude is not null and exclude is null cursor will have only include
843+ -- If exclude is not null and include is null cursor will have all except exclude
844+
845+ if a_include_xpath.count > 0 and a_exclude_xpath.count > 0 then
846+ select col_names bulk collect into l_filtered_set
847+ from(
848+ select regexp_replace(column_value,'^((/ROW/)|^(//)|^(/\*/))?(.*)','\5') col_names
849+ from table(a_include_xpath)
850+ minus
851+ select regexp_replace(column_value,'^((/ROW/)|^(//)|^(/\*/))?(.*)','\5') col_names
852+ from table(a_exclude_xpath)
853+ );
854+ elsif a_include_xpath.count > 0 and a_exclude_xpath.count = 0 then
855+ select regexp_replace(column_value,'^((/ROW/)|^(//)|^(/\*/))?(.*)','\5') col_names
856+ bulk collect into l_filtered_set
857+ from table(a_include_xpath);
858+ elsif a_include_xpath.count = 0 and a_exclude_xpath.count > 0 then
859+ select regexp_replace(column_value,'^((/ROW/)|^(//)|^(/\*/))?(.*)','\5') col_names
860+ bulk collect into l_filtered_set
861+ from table(a_exclude_xpath);
862+ elsif a_cursor_info is not null then
863+ l_result:= a_cursor_info;
864+ else
865+ l_result := ut_column_info_tab();
866+ end if;
867+
868+ g_filter_tab := l_filtered_set;
869+ if g_filter_tab.count <> 0 then
870+ l_result := exc_inc_cursors_columns(a_cursor_info,get_child());
871+ end if;
872+
873+ return l_result;
874+ end;
875+
876+ end;
752877/
0 commit comments