@@ -39,15 +39,14 @@ create or replace package body ut_annotation_parser as
3939 ,modifier => 'n');
4040 end;
4141
42- function get_annotations(a_source varchar2, a_comments tt_comment_list) return tt_annotations is
43- l_loop_index pls_integer := 1;
44- l_comment_index pls_integer;
45- l_comment varchar2(32767);
46- l_annotation_str varchar2(32767);
47- l_annotation_text varchar2(32767);
48- l_annotation_name varchar2(1000);
49- l_annotation t_annotation;
50- l_annotations_list tt_annotations;
42+ function get_annotations(a_source varchar2, a_comments tt_comment_list, a_subobject_name varchar2 := null) return ut_annotations is
43+ l_loop_index pls_integer := 1;
44+ l_annotation_index pls_integer;
45+ l_comment varchar2(32767);
46+ l_annotation_str varchar2(32767);
47+ l_annotation_text varchar2(32767);
48+ l_annotation_name varchar2(1000);
49+ l_annotations ut_annotations := ut_annotations();
5150 begin
5251 -- loop while there are unprocessed comment blocks
5352 while 0 != nvl(regexp_instr(srcstr => a_source
@@ -57,13 +56,13 @@ create or replace package body ut_annotation_parser as
5756 ,0) loop
5857
5958 -- define index of the comment block and get it's content from cache
60- l_comment_index := to_number(regexp_substr(a_source
59+ l_annotation_index := to_number(regexp_substr(a_source
6160 ,c_comment_replacer_regex_ptrn
6261 ,1
6362 ,l_loop_index
6463 ,subexpression => 1));
6564
66- l_comment := a_comments(l_comment_index );
65+ l_comment := a_comments( l_annotation_index );
6766
6867 -- strip everything except the annotation itself (spaces and others)
6968 l_annotation_str := regexp_substr(l_comment, c_annotation_pattern, 1, 1, modifier => 'i');
@@ -76,38 +75,39 @@ create or replace package body ut_annotation_parser as
7675 ,subexpression => 1));
7776 l_annotation_text := trim(regexp_substr(l_annotation_str, '\((.*?)\)\s*$', subexpression => 1));
7877
79- l_annotation.text := l_annotation_text;
80- l_annotations_list(l_annotation_name) := l_annotation;
78+ l_annotations.extend;
79+ l_annotations( l_annotations.last) :=
80+ ut_annotation(l_annotation_index, l_annotation_name, l_annotation_text, a_subobject_name);
8181 end if;
8282 l_loop_index := l_loop_index + 1;
8383 end loop;
84-
85- return l_annotations_list;
84+ return l_annotations;
8685
8786 end get_annotations;
8887
89- function get_package_annotations(a_source clob, a_comments tt_comment_list) return tt_annotations is
88+ function get_package_annotations(a_source clob, a_comments tt_comment_list) return ut_annotations is
9089 l_package_comments varchar2(32767);
90+ l_annotations ut_annotations := ut_annotations();
9191 begin
9292 l_package_comments := regexp_substr(srcstr => a_source
9393 ,pattern => '^\s*(CREATE\s+(OR\s+REPLACE)?(\s+(NON)?EDITIONABLE)?\s+)?PACKAGE\s[^;]*?(\s+(AS|IS)\s+)((.*?{COMMENT#\d+}\s?)+)'
9494 ,modifier => 'i'
9595 ,subexpression => 7);
9696
9797 -- parsing for package annotations
98- return
99- case when l_package_comments is not null then
100- get_annotations(l_package_comments, a_comments)
101- end;
98+ if l_package_comments is not null then
99+ l_annotations := get_annotations(l_package_comments, a_comments);
100+ end if;
101+
102+ return l_annotations;
102103 end;
103104
104- function get_procedure_list(a_source clob, a_comments tt_comment_list) return tt_procedure_list is
105+ function get_procedure_list(a_source clob, a_comments tt_comment_list) return ut_annotations is
105106 l_proc_comments varchar2(32767);
106107 l_proc_name t_annotation_name;
107108 l_annot_proc_ind number;
108109 l_annot_proc_block varchar2(32767);
109- l_procedure_annotations tt_procedure_annotations;
110- l_procedure_list tt_procedure_list;
110+ l_annotations ut_annotations := ut_annotations();
111111 begin
112112 -- loop through procedures and functions of the package and get all the comment blocks just before it's declaration
113113 l_annot_proc_ind := 1;
@@ -139,18 +139,16 @@ create or replace package body ut_annotation_parser as
139139 ,subexpression => 5));
140140
141141 -- parse the comment block for the syntactically correct annotations and store them as an array
142- l_procedure_annotations.name := l_proc_name;
143- l_procedure_annotations.annotations := get_annotations(l_proc_comments, a_comments);
144-
145- l_procedure_list(l_procedure_list.count+1) := l_procedure_annotations;
142+ l_annotations := l_annotations multiset union all get_annotations(l_proc_comments, a_comments, l_proc_name);
146143
147144 --l_annot_proc_ind := l_annot_proc_ind + length(l_annot_proc_block);
148145 l_annot_proc_ind := regexp_instr(srcstr => a_source
149146 ,pattern => ';'
150147 ,occurrence => 1
151148 ,position => l_annot_proc_ind + length(l_annot_proc_block));
152149 end loop;
153- return l_procedure_list;
150+
151+ return l_annotations;
154152 end;
155153
156154 function extract_and_replace_comments(a_source in out nocopy clob) return tt_comment_list is
@@ -199,62 +197,21 @@ create or replace package body ut_annotation_parser as
199197 return l_comments;
200198 end extract_and_replace_comments;
201199
202- -- $if $$ut_trace $then
203- -- procedure print_parse_results(a_annotated_pkg typ_annotated_package) is
204- -- l_name t_annotation_name := a_annotated_pkg.package_annotations.first;
205- -- l_proc_name t_annotation_name;
206- -- begin
207- -- dbms_output.put_line('Annotations count: ' || a_annotated_pkg.package_annotations.count);
208- --
209- -- while l_name is not null loop
210- -- dbms_output.put_line(' @' || l_name);
211- -- if a_annotated_pkg.package_annotations(l_name).count > 0 then
212- -- dbms_output.put_line(' Parameters:');
213- --
214- -- for j in 1 .. a_annotated_pkg.package_annotations(l_name).count loop
215- -- dbms_output.put_line(' ' || nvl(a_annotated_pkg.package_annotations(l_name)(j).key, '<Anonymous>') || ' = ' ||
216- -- nvl(a_annotated_pkg.package_annotations(l_name)(j).val, 'NULL'));
217- -- end loop;
218- -- else
219- -- dbms_output.put_line(' No parameters.');
220- -- end if;
221- --
222- -- l_name := a_annotated_pkg.package_annotations.next(l_name);
223- --
224- -- end loop;
225- --
226- -- dbms_output.put_line('Procedures count: ' || a_annotated_pkg.procedure_annotations.count);
227- --
228- -- for i in 1 .. a_annotated_pkg.procedure_annotations.count loop
229- -- l_proc_name := a_annotated_pkg.procedure_annotations(i).name;
230- -- dbms_output.put_line(rpad('-', 80, '-'));
231- -- dbms_output.put_line(' Procedure: ' || l_proc_name);
232- -- dbms_output.put_line(' Annotations count: ' || a_annotated_pkg.procedure_annotations(i).annotations.count);
233- -- l_name := a_annotated_pkg.procedure_annotations(i).annotations.first;
234- -- while l_name is not null loop
235- -- dbms_output.put_line(' @' || l_name);
236- -- if a_annotated_pkg.procedure_annotations(i).annotations(l_name).count > 0 then
237- -- dbms_output.put_line(' Parameters:');
238- -- for j in 1 .. a_annotated_pkg.procedure_annotations(i).annotations(l_name).count loop
239- -- dbms_output.put_line(' ' ||
240- -- nvl(a_annotated_pkg.procedure_annotations(i).annotations(l_name)(j).key, '<Anonymous>') ||
241- -- ' = ' || nvl(a_annotated_pkg.procedure_annotations(i).annotations(l_name)(j).val, 'NULL'));
242- -- end loop;
243- -- else
244- -- dbms_output.put_line(' No parameters.');
245- -- end if;
246- --
247- -- l_name := a_annotated_pkg.procedure_annotations(i).annotations.next(l_name);
248- -- end loop;
249- -- end loop;
250- --
251- -- end print_parse_results;
252- -- $end
253-
254- function parse_package_annotations(a_source clob) return typ_annotated_package is
200+ $if $$ut_trace $then
201+ procedure print_parse_results(a_annotations ut_annotations) is
202+ begin
203+ dbms_output.put_line('Annotations count: ' || a_annotations.count);
204+ for i in 1 .. a_annotations.count loop
205+ dbms_output.put_line(xmltype(a_annotations(i)).getclobval());
206+ end loop;
207+ end print_parse_results;
208+ $end
209+
210+ function parse_package_annotations(a_source clob) return ut_annotations is
255211 l_source clob := a_source;
256212 l_comments tt_comment_list;
257- l_annotated_pkg typ_annotated_package;
213+ l_annotations ut_annotations;
214+ l_result ut_annotations;
258215 begin
259216
260217 l_source := delete_multiline_comments(l_source);
@@ -263,53 +220,37 @@ create or replace package body ut_annotation_parser as
263220 -- this call modifies l_source
264221 l_comments := extract_and_replace_comments(l_source);
265222
266- l_annotated_pkg.package_annotations := get_package_annotations(l_source, l_comments);
267-
268- l_annotated_pkg.procedure_annotations := get_procedure_list(l_source, l_comments);
269-
270- -- -- printing out parsed structure for debugging
271- -- $if $$ut_trace $then
272- -- print_parse_results(l_annotated_pkg);
273- -- $end
223+ l_annotations :=
224+ get_package_annotations(l_source, l_comments)
225+ multiset union all get_procedure_list(l_source, l_comments);
274226
275227 dbms_lob.freetemporary(l_source);
276- return l_annotated_pkg;
228+ select value(x)
229+ bulk collect into l_result
230+ from table(l_annotations) x
231+ order by x.position;
232+
233+ -- printing out parsed structure for debugging
234+ $if $$ut_trace $then
235+ print_parse_results(l_result);
236+ $end
237+ return l_result;
277238 end parse_package_annotations;
278239
279240 ------------------------------
280241 --public definitions
281242
282- function get_package_annotations(a_owner_name varchar2, a_name varchar2) return typ_annotated_package is
243+ function get_package_annotations(a_owner_name varchar2, a_name varchar2) return ut_annotations is
283244 l_source clob;
284245 ex_package_is_wrapped exception;
285246 pragma exception_init(ex_package_is_wrapped, -24241);
286247 begin
287-
288- -- TODO: Add cache of annotations. Cache invalidation should be based on DDL timestamp.
289- -- Cache garbage collection should be executed once in a while to remove annotations cache for packages that were dropped.
290-
291- begin
292- l_source := ut_metadata.get_package_spec_source(a_owner_name, a_name);
293- exception
294- when ex_package_is_wrapped then
295- null;
296- end;
297-
298- if l_source is null or sys.dbms_lob.getlength(l_source)=0 then
299- return null;
300- else
301- return parse_package_annotations(l_source);
302- end if;
248+ return parse_package_annotations(ut_metadata.get_package_spec_source(a_owner_name, a_name));
249+ exception
250+ when ex_package_is_wrapped then
251+ return ut_annotations();
303252 end;
304253
305- -- function get_annotation_param(a_param_list tt_annotation_params, a_def_index pls_integer) return varchar2 is
306- -- l_result varchar2(32767);
307- -- begin
308- -- if a_param_list.exists(a_def_index) then
309- -- l_result := a_param_list(a_def_index).val;
310- -- end if;
311- -- return l_result;
312- -- end get_annotation_param;
313254
314255 -- parse the annotation parameters and return as key-value pair array
315256 function parse_annotation_params(a_annotation_text varchar2) return tt_annotation_params is
0 commit comments