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

Skip to content

Commit 9961dbc

Browse files
committed
Testing fix for issue with cursors
1 parent 09b43da commit 9961dbc

5 files changed

Lines changed: 93 additions & 55 deletions

File tree

source/expectations/data_values/ut_cursor_column.tpb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@ create or replace type body ut_cursor_column as
2626
end; --when is nestd we need to hash name to make sure we dont exceed 30 char
2727
self.column_type := a_col_type; --column type e.g. user_defined , varchar2
2828
self.column_schema := a_col_schema_name; -- schema name
29-
self.is_sql_diffable := case when lower(self.column_type) = 'user_defined_type' then
29+
self.is_sql_diffable := case
30+
when lower(self.column_type) = 'user_defined_type' then
3031
0
32+
-- Due to bug in 11g/12.1 collection fails on varchar 4000+
33+
when (lower(self.column_type) in ('varchar2','char')) and (self.column_len >= 4000) then
34+
0
3135
else
3236
ut_utils.boolean_to_int(ut_compound_data_helper.is_sql_compare_allowed(self.column_type))
3337
end; --can we directly compare or do we need to hash value

source/expectations/data_values/ut_data_value_anydata.tpb

Lines changed: 83 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,72 @@ create or replace type body ut_data_value_anydata as
2121
return self.data_type || case when self.compound_type = 'collection' then ' [ count = '||self.elements_count||' ]' else null end;
2222
end;
2323

24-
member procedure get_cursor_from_anydata(self in out nocopy ut_data_value_anydata, a_value in anydata,
25-
a_refcursor out nocopy sys_refcursor) is
24+
member function get_extract_path(a_data_value anydata) return varchar2 is
25+
l_path varchar2(10);
26+
begin
27+
if self.compound_type = 'object' then
28+
l_path := '/*/*';
29+
else
30+
case when ut_metadata.has_collection_members(a_data_value) then
31+
l_path := '/*/*';
32+
else
33+
l_path := '/*';
34+
end case;
35+
end if;
36+
return l_path;
37+
end;
38+
39+
overriding member procedure extract_cursor(self in out nocopy ut_data_value_anydata, a_value sys_refcursor)
40+
is
41+
c_bulk_rows constant integer := 10000;
42+
l_cursor sys_refcursor := a_value;
43+
l_ctx number;
44+
l_xml xmltype;
45+
l_ut_owner varchar2(250) := ut_utils.ut_owner;
46+
l_set_id integer := 0;
47+
l_elements_count number := 0;
48+
begin
49+
-- We use DBMS_XMLGEN in order to:
50+
-- 1) be able to process data in bulks (set of rows)
51+
-- 2) be able to influence the ROWSET/ROW tags
52+
-- 3) be able to influence the way NULL values are handled (empty TAG)
53+
-- 4) be able to influence the way TIMESTAMP is formatted.
54+
-- Due to Oracle feature/bug, it is not possible to change the DATE formatting of cursor data
55+
-- AFTER the cursor was opened.
56+
-- The only solution for this is to change NLS settings before opening the cursor.
57+
--
58+
-- This would work fine if we could use DBMS_XMLGEN.restartQuery.
59+
-- The restartQuery fails however if PLSQL variables of TIMESTAMP/INTERVAL or CLOB/BLOB are used.
60+
ut_expectation_processor.set_xml_nls_params();
61+
l_ctx := dbms_xmlgen.newContext(l_cursor);
62+
dbms_xmlgen.setNullHandling(l_ctx, dbms_xmlgen.empty_tag);
63+
dbms_xmlgen.setMaxRows(l_ctx, c_bulk_rows);
64+
loop
65+
l_xml := dbms_xmlgen.getxmltype(l_ctx);
66+
exit when dbms_xmlgen.getNumRowsProcessed(l_ctx) = 0;
67+
l_elements_count := l_elements_count + dbms_xmlgen.getNumRowsProcessed(l_ctx);
68+
execute immediate
69+
'insert into ' || l_ut_owner || '.ut_compound_data_tmp(data_id, item_no, item_data) ' ||
70+
'values (:self_guid, :self_row_count, :l_xml)'
71+
using in self.data_id, l_set_id, l_xml;
72+
l_set_id := l_set_id + c_bulk_rows;
73+
end loop;
74+
ut_expectation_processor.reset_nls_params();
75+
dbms_xmlgen.closeContext(l_ctx);
76+
self.elements_count := l_elements_count;
77+
exception
78+
when others then
79+
ut_expectation_processor.reset_nls_params();
80+
dbms_xmlgen.closeContext(l_ctx);
81+
raise;
82+
end;
83+
84+
member procedure init(self in out nocopy ut_data_value_anydata, a_value anydata) is
85+
l_refcursor sys_refcursor;
86+
l_ctx number;
87+
l_ut_owner varchar2(250) := ut_utils.ut_owner;
88+
cursor_not_open exception;
89+
l_cursor_number number;
2690
l_anydata_sql varchar2(4000);
2791
l_cursor_sql varchar2(2000);
2892

@@ -45,14 +109,25 @@ create or replace type body ut_data_value_anydata as
45109
return resolve_name(a_datatype);
46110
end;
47111

48-
begin
49-
l_anydata_sql := '
112+
begin
113+
self.data_type := ut_metadata.get_anydata_typename(a_value);
114+
self.compound_type := get_instance(a_value);
115+
self.is_data_null := ut_metadata.is_anytype_null(a_value,self.compound_type);
116+
self.data_id := sys_guid();
117+
self.self_type := $$plsql_unit;
118+
self.cursor_details := ut_cursor_details();
119+
120+
ut_compound_data_helper.cleanup_diff;
121+
122+
if not self.is_null() then
123+
self.extract_path := get_extract_path(a_value);
124+
--get_cursor_from_anydata(a_value,l_refcursor);
125+
l_anydata_sql := '
50126
declare
51127
l_data '||self.data_type||';
52128
l_value anydata := :a_value;
53129
l_status integer;
54130
l_tmp_refcursor sys_refcursor;
55-
l_refcursor sys_refcursor;
56131
begin
57132
l_status := l_value.get'||self.compound_type||'(l_data); '||
58133
case when self.compound_type = 'collection' then
@@ -61,46 +136,10 @@ create or replace type body ut_data_value_anydata as
61136
q'[ open :l_tmp_refcursor for select l_data as "]'||get_object_name(self.data_type)||q'[" from dual;]'
62137
end ||
63138
'end;';
64-
execute immediate l_anydata_sql using in a_value, in out a_refcursor;
65-
end;
66-
67-
member function get_extract_path(a_data_value anydata) return varchar2 is
68-
l_path varchar2(10);
69-
begin
70-
if self.compound_type = 'object' then
71-
l_path := '/*/*';
72-
else
73-
case when ut_metadata.has_collection_members(a_data_value) then
74-
l_path := '/*/*';
75-
else
76-
l_path := '/*';
77-
end case;
78-
end if;
79-
return l_path;
80-
end;
81-
82-
member procedure init(self in out nocopy ut_data_value_anydata, a_value anydata) is
83-
l_refcursor sys_refcursor;
84-
l_ctx number;
85-
l_ut_owner varchar2(250) := ut_utils.ut_owner;
86-
cursor_not_open exception;
87-
l_cursor_number number;
88-
89-
begin
90-
self.data_type := ut_metadata.get_anydata_typename(a_value);
91-
self.compound_type := get_instance(a_value);
92-
self.is_data_null := ut_metadata.is_anytype_null(a_value,self.compound_type);
93-
self.data_id := sys_guid();
94-
self.self_type := $$plsql_unit;
95-
self.cursor_details := ut_cursor_details();
96-
97-
ut_compound_data_helper.cleanup_diff;
98-
99-
if not self.is_null() then
100-
self.extract_path := get_extract_path(a_value);
101-
get_cursor_from_anydata(a_value,l_refcursor);
139+
execute immediate l_anydata_sql using in a_value, in out l_refcursor;
140+
102141
if l_refcursor%isopen then
103-
self.elements_count := self.extract_cursor(l_refcursor);
142+
extract_cursor(l_refcursor);
104143
l_cursor_number := dbms_sql.to_cursor_number(l_refcursor);
105144
self.cursor_details := ut_cursor_details(l_cursor_number);
106145
dbms_sql.close_cursor(l_cursor_number);
@@ -109,7 +148,6 @@ create or replace type body ut_data_value_anydata as
109148
end if;
110149
end if;
111150

112-
113151
exception
114152
when cursor_not_open then
115153
raise_application_error(-20155, 'Cursor is not open');

source/expectations/data_values/ut_data_value_anydata.tps

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@ create or replace type ut_data_value_anydata under ut_data_value_refcursor(
1616
limitations under the License.
1717
*/
1818

19-
20-
member procedure get_cursor_from_anydata(self in out nocopy ut_data_value_anydata, a_value in anydata,
21-
a_refcursor out nocopy sys_refcursor),
2219
overriding member function get_object_info return varchar2,
2320
member function get_extract_path(a_data_value anydata) return varchar2,
21+
overriding member procedure extract_cursor(self in out nocopy ut_data_value_anydata, a_value sys_refcursor),
2422
member procedure init(self in out nocopy ut_data_value_anydata, a_value anydata),
2523
member function get_instance(a_data_value anydata) return varchar2,
2624
constructor function ut_data_value_anydata(self in out nocopy ut_data_value_anydata, a_value anydata) return self as result,

source/expectations/data_values/ut_data_value_refcursor.tpb

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ create or replace type body ut_data_value_refcursor as
2323
return;
2424
end;
2525

26-
member function extract_cursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor)
27-
return number
26+
member procedure extract_cursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor)
2827
is
2928
c_bulk_rows constant integer := 10000;
3029
l_cursor sys_refcursor := a_value;
@@ -45,7 +44,6 @@ create or replace type body ut_data_value_refcursor as
4544
--
4645
-- This would work fine if we could use DBMS_XMLGEN.restartQuery.
4746
-- The restartQuery fails however if PLSQL variables of TIMESTAMP/INTERVAL or CLOB/BLOB are used.
48-
4947
ut_expectation_processor.set_xml_nls_params();
5048
l_ctx := dbms_xmlgen.newContext(l_cursor);
5149
dbms_xmlgen.setNullHandling(l_ctx, dbms_xmlgen.empty_tag);
@@ -62,7 +60,7 @@ create or replace type body ut_data_value_refcursor as
6260
end loop;
6361
ut_expectation_processor.reset_nls_params();
6462
dbms_xmlgen.closeContext(l_ctx);
65-
return l_elements_count;
63+
self.elements_count := l_elements_count;
6664
exception
6765
when others then
6866
ut_expectation_processor.reset_nls_params();
@@ -87,7 +85,7 @@ create or replace type body ut_data_value_refcursor as
8785
if l_cursor is not null then
8886
if l_cursor%isopen then
8987
--Get some more info regarding cursor, including if it containts collection columns and what is their name
90-
self.elements_count := extract_cursor(l_cursor);
88+
extract_cursor(l_cursor);
9189
l_cursor_number := dbms_sql.to_cursor_number(l_cursor);
9290
self.cursor_details := ut_cursor_details(l_cursor_number);
9391
dbms_sql.close_cursor(l_cursor_number);

source/expectations/data_values/ut_data_value_refcursor.tps

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ create or replace type ut_data_value_refcursor under ut_compound_data_value(
3636
extract_path varchar2(10),
3737

3838
constructor function ut_data_value_refcursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor) return self as result,
39-
member function extract_cursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor) return number,
39+
member procedure extract_cursor(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor),
4040
member procedure init(self in out nocopy ut_data_value_refcursor, a_value sys_refcursor),
4141
overriding member function to_string return varchar2,
4242
overriding member function diff( a_other ut_data_value, a_match_options ut_matcher_options ) return varchar2,

0 commit comments

Comments
 (0)