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

Skip to content

Commit 3bdd540

Browse files
authored
Fixing issue with a special column names non XML compliant (#903)
* Fixing issue with a special column names that do not adhere to XML rules. * removing unused global constant. * Modification after PR comments. Inline call to function. Remove constants to be private. Expose only one function rest to be private
1 parent 0e2eaa5 commit 3bdd540

7 files changed

Lines changed: 144 additions & 17 deletions

File tree

source/core/ut_utils.pkb

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ create or replace package body ut_utils is
1616
limitations under the License.
1717
*/
1818

19+
/**
20+
* Constants regex used to validate XML name
21+
*/
22+
gc_invalid_first_xml_char constant varchar2(50) := '[^_a-zA-Z]';
23+
gc_invalid_xml_char constant varchar2(50) := '[^_a-zA-Z0-9\.-]';
24+
gc_full_valid_xml_name constant varchar2(50) := '^([_a-zA-Z])([_a-zA-Z0-9\.-])*$';
25+
1926
function surround_with(a_value varchar2, a_quote_char varchar2) return varchar2 is
2027
begin
2128
return case when a_quote_char is not null then a_quote_char||a_value||a_quote_char else a_value end;
@@ -749,8 +756,47 @@ create or replace package body ut_utils is
749756
,modifier => 'm');
750757
return l_caller_stack_line;
751758
end;
752-
753-
759+
760+
/**
761+
* Change string into unicode to match xmlgen format _00<unicode>_
762+
* https://docs.oracle.com/en/database/oracle/oracle-database/12.2/adxdb/generation-of-XML-data-from-relational-data.html#GUID-5BE09A7D-80D8-4734-B9AF-4A61F27FA9B2
763+
* secion 8.2.1.1
764+
*/
765+
function char_to_xmlgen_unicode(a_character varchar2) return varchar2 is
766+
begin
767+
return '_x00'||rawtohex(utl_raw.cast_to_raw(a_character))||'_';
768+
end;
769+
770+
/**
771+
* Build valid XML column name as element names can contain letters, digits, hyphens, underscores, and periods
772+
*/
773+
function build_valid_xml_name(a_preprocessed_name varchar2) return varchar2 is
774+
l_post_processed varchar2(4000);
775+
begin
776+
for i in (select regexp_substr( a_preprocessed_name ,'(.{1})', 1, level, null, 1 ) AS string_char,level level_no
777+
from dual connect by level <= regexp_count(a_preprocessed_name, '(.{1})'))
778+
loop
779+
if i.level_no = 1 and regexp_like(i.string_char,gc_invalid_first_xml_char) then
780+
l_post_processed := l_post_processed || char_to_xmlgen_unicode(i.string_char);
781+
elsif regexp_like(i.string_char,gc_invalid_xml_char) then
782+
l_post_processed := l_post_processed || char_to_xmlgen_unicode(i.string_char);
783+
else
784+
l_post_processed := l_post_processed || i.string_char;
785+
end if;
786+
end loop;
787+
return l_post_processed;
788+
end;
789+
790+
function get_valid_xml_name(a_name varchar2) return varchar2 is
791+
l_valid_name varchar2(4000);
792+
begin
793+
if regexp_like(a_name,gc_full_valid_xml_name) then
794+
l_valid_name := a_name;
795+
else
796+
l_valid_name := build_valid_xml_name(a_name);
797+
end if;
798+
return l_valid_name;
799+
end;
754800

755801
end ut_utils;
756802
/

source/core/ut_utils.pks

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ create or replace package ut_utils authid definer is
2222
*/
2323

2424
gc_version constant varchar2(50) := 'v3.1.7.2844-develop';
25-
25+
2626
subtype t_executable_type is varchar2(30);
2727
gc_before_all constant t_executable_type := 'beforeall';
2828
gc_before_each constant t_executable_type := 'beforeeach';
@@ -381,6 +381,11 @@ create or replace package ut_utils authid definer is
381381
* Remove given ORA error from stack
382382
*/
383383
function remove_error_from_stack(a_error_stack varchar2, a_ora_code number) return varchar2;
384-
384+
385+
/**
386+
* Check if xml name is valid if not build a valid name
387+
*/
388+
function get_valid_xml_name(a_name varchar2) return varchar2;
389+
385390
end ut_utils;
386391
/

source/expectations/data_values/ut_compound_data_helper.pkb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ create or replace package body ut_compound_data_helper is
8080
begin
8181
execute immediate q'[with
8282
expected_cols as (
83-
select access_path exp_column_name,column_position exp_col_pos,
83+
select display_path exp_column_name,column_position exp_col_pos,
8484
replace(column_type_name,'VARCHAR2','CHAR') exp_col_type_compare, column_type_name exp_col_type
8585
from table(:a_expected)
8686
where parent_name is null and hierarchy_level = 1 and column_name is not null
8787
),
8888
actual_cols as (
89-
select access_path act_column_name,column_position act_col_pos,
89+
select display_path act_column_name,column_position act_col_pos,
9090
replace(column_type_name,'VARCHAR2','CHAR') act_col_type_compare, column_type_name act_col_type
9191
from table(:a_actual)
9292
where parent_name is null and hierarchy_level = 1 and column_name is not null

source/expectations/data_values/ut_cursor_column.tpb

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,24 @@ create or replace type body ut_cursor_column as
1313
self.column_len := a_col_max_len; --length of column
1414
self.column_name := TRIM( BOTH '''' FROM a_col_name); --name of the column
1515
self.column_type_name := coalesce(a_col_type_name,a_col_type); --type name e.g. test_dummy_object or varchar2
16-
self.access_path := case when a_access_path is null then
16+
self.xml_valid_name := ut_utils.get_valid_xml_name(self.column_name);
17+
self.display_path := case when a_access_path is null then
1718
self.column_name
1819
else
1920
a_access_path||'/'||self.column_name
20-
end; --Access path used for incldue exclude eg/ TEST_DUMMY_OBJECT/VARCHAR2
21-
self.xml_valid_name := '"'||self.column_name||'"'; --User friendly column name
22-
self.transformed_name := case when self.parent_name is null then
23-
self.xml_valid_name
24-
else
25-
'"'||ut_compound_data_helper.get_fixed_size_hash(self.parent_name||self.column_name)||'"'
26-
end; --when is nestd we need to hash name to make sure we dont exceed 30 char
21+
end; --Access path used for incldue exclude eg/ TEST_DUMMY_OBJECT/VARCHAR2
22+
self.access_path := case when a_access_path is null then
23+
self.xml_valid_name
24+
else
25+
a_access_path||'/'||self.xml_valid_name
26+
end; --Access path used for incldue exclude eg/ TEST_DUMMY_OBJECT/VARCHAR2
27+
self.transformed_name := case when length(self.xml_valid_name) > 30 then
28+
'"'||ut_compound_data_helper.get_fixed_size_hash(self.parent_name||self.xml_valid_name)||'"'
29+
when self.parent_name is null then
30+
'"'||self.xml_valid_name||'"'
31+
else
32+
'"'||ut_compound_data_helper.get_fixed_size_hash(self.parent_name||self.xml_valid_name)||'"'
33+
end; --when is nestd we need to hash name to make sure we dont exceed 30 char
2734
self.column_type := a_col_type; --column type e.g. user_defined , varchar2
2835
self.column_schema := a_col_schema_name; -- schema name
2936
self.is_sql_diffable := case

source/expectations/data_values/ut_cursor_column.tps

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ create or replace type ut_cursor_column force authid current_user as object (
1717
*/
1818
parent_name varchar2(4000),
1919
access_path varchar2(4000),
20+
display_path varchar2(4000),
2021
has_nested_col number(1,0),
21-
transformed_name varchar2(32),
22+
transformed_name varchar2(2000),
2223
hierarchy_level number,
2324
column_position number,
24-
xml_valid_name varchar2(128),
25-
column_name varchar2(128),
25+
xml_valid_name varchar2(2000),
26+
column_name varchar2(2000),
2627
column_type varchar2(128),
2728
column_type_name varchar2(128),
2829
column_schema varchar2(128),

test/ut3_user/expectations/test_expectations_cursor.pkb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2618,5 +2618,64 @@ Check the query and data for errors.';
26182618
ut3.ut.reset_nls;
26192619

26202620
end;
2621+
2622+
procedure colon_part_of_columnname is
2623+
type t_key_val_rec is record(
2624+
key varchar2(100),
2625+
value varchar2(100));
2626+
2627+
l_act t_key_val_rec;
2628+
l_exp t_key_val_rec;
2629+
l_act_cur sys_refcursor;
2630+
l_exp_cur sys_refcursor;
2631+
begin
2632+
l_act.key := 'NAME';
2633+
l_act.value := 'TEST';
2634+
l_exp.key := 'NAME';
2635+
l_exp.value := 'TEST';
2636+
2637+
OPEN l_act_cur FOR SELECT l_act.key, l_act.value
2638+
FROM dual;
2639+
2640+
OPEN l_exp_cur FOR SELECT l_exp.key, l_exp.value
2641+
FROM dual;
2642+
2643+
ut3.ut.expect(l_act_cur).to_equal(l_exp_cur);
2644+
ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0);
2645+
2646+
end;
2647+
2648+
procedure specialchar_part_of_colname is
2649+
l_act_cur sys_refcursor;
2650+
l_exp_cur sys_refcursor;
2651+
begin
2652+
2653+
OPEN l_act_cur FOR SELECT 1 as "$Test", 2 as "&Test"
2654+
FROM dual;
2655+
2656+
OPEN l_exp_cur FOR SELECT 1 as "$Test", 2 as "&Test"
2657+
FROM dual;
2658+
2659+
ut3.ut.expect(l_act_cur).to_equal(l_exp_cur);
2660+
ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0);
2661+
2662+
end;
2663+
2664+
procedure nonxmlchar_part_of_colname is
2665+
l_act_cur sys_refcursor;
2666+
l_exp_cur sys_refcursor;
2667+
begin
2668+
2669+
OPEN l_act_cur FOR SELECT 1 as "<Test>", 2 as "_Test", 3 as ".Test>"
2670+
FROM dual;
2671+
2672+
OPEN l_exp_cur FOR SELECT 1 as "<Test>", 2 as "_Test", 3 as ".Test>"
2673+
FROM dual;
2674+
2675+
ut3.ut.expect(l_act_cur).to_equal(l_exp_cur);
2676+
ut.expect(ut3_tester_helper.main_helper.get_failed_expectations_num).to_equal(0);
2677+
2678+
end;
2679+
26212680
end;
26222681
/

test/ut3_user/expectations/test_expectations_cursor.pks

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,15 @@ create or replace package test_expectations_cursor is
408408

409409
--%test(Check that cursor correctly handles no length dataypes)
410410
procedure no_length_datatypes;
411+
412+
--%test(Check that colon is converted properly fix #902)
413+
procedure colon_part_of_columnname;
414+
415+
--%test(Check that column name accept special characters fix #902)
416+
procedure specialchar_part_of_colname;
417+
418+
--%test(Check that column name accept non xml characters fix #902)
419+
procedure nonxmlchar_part_of_colname;
411420

412421
end;
413422
/

0 commit comments

Comments
 (0)