@@ -230,15 +230,138 @@ create or replace package body ut_annotation_parser as
230230 from table(l_annotations) x
231231 order by x.position;
232232
233- -- printing out parsed structure for debugging
234- $if $$ut_trace $then
235- print_parse_results(l_result);
236- $end
233+ -- -- printing out parsed structure for debugging
234+ -- $if $$ut_trace $then
235+ -- print_parse_results(l_result);
236+ -- $end
237237 return l_result;
238238 end parse_package_annotations;
239239
240- ------------------------------
240+ function get_post_processed_source(a_source_lines ut_varchar2_rows) return clob is
241+ l_lines sys.dbms_preprocessor.source_lines_t;
242+ l_source clob;
243+ begin
244+ --convert to preprocessor lines
245+ for i in 1 .. a_source_lines.count loop
246+ l_lines(i) := a_source_lines(i);
247+ end loop;
248+ --get post-processed source
249+ l_lines := sys.dbms_preprocessor.get_post_processed_source(l_lines);
250+ --convert to clob
251+ for i in 1..l_lines.count loop
252+ ut_utils.append_to_clob(l_source, replace(l_lines(i), chr(13)||chr(10), chr(10)));
253+ end loop;
254+ return l_source;
255+ end;
256+
257+ ------------------------------------------------------------
241258 --public definitions
259+ ------------------------------------------------------------
260+
261+ function parse_annotations(a_cursor t_object_sources_cur) return ut_annotated_objects pipelined is
262+ l_rec t_object_source;
263+ l_source clob;
264+ l_annotations ut_annotations;
265+ l_result ut_annotated_object;
266+ ex_package_is_wrapped exception;
267+ pragma exception_init(ex_package_is_wrapped, -24241);
268+
269+ begin
270+ if not a_cursor% isopen then
271+ return;
272+ end if;
273+ loop
274+
275+ fetch a_cursor into l_rec;
276+ exit when a_cursor%notfound;
277+ begin
278+ --convert to post-processed source clob
279+ l_source := get_post_processed_source(l_rec.lines);
280+ --parse annotations
281+ l_annotations := parse_package_annotations(l_source);
282+ dbms_lob.freetemporary(l_source);
283+ exception
284+ when ex_package_is_wrapped then
285+ null;
286+ end;
287+ --convert to query results
288+ l_result := ut_annotated_object( l_rec.owner, l_rec.name, l_rec.type, l_annotations);
289+
290+ ut_annotation_cache_manager.update_cache(l_result, l_rec.cache_id);
291+ if l_annotations is not empty then
292+ pipe row (l_result);
293+ end if;
294+ end loop;
295+ close a_cursor;
296+ return;
297+ end;
298+
299+
300+ function get_annotated_objects(a_object_owner varchar2, a_object_type varchar2) return ut_annotated_objects pipelined is
301+ l_objects_view varchar2(200) := ut_metadata.get_dba_view('dba_objects');
302+ l_sources_view varchar2(200) := ut_metadata.get_dba_view('dba_source');
303+ l_obj ut_annotated_object;
304+ l_current_schema varchar2(250) := ut_utils.ut_owner;
305+ l_cursor sys_refcursor;
306+ l_cursor_sql varchar2(32767);
307+ begin
308+ l_cursor_sql :=
309+ q'[with object_cache_info
310+ as (select /*+ cardinality(i 10000) */ o.owner as object_owner, o.object_name, o.object_type, i.cache_id,
311+ case when o.last_ddl_time < i.parse_time then 'N' else 'Y' end as cache_stale
312+ from ]'||l_objects_view||q'[ o
313+ left join ]'||l_current_schema||q'[.ut_annotation_cache_info i
314+ on o.owner = i.object_owner and o.object_name = i.object_name and o.object_type = i.object_type
315+ where o.object_type = :a_object_type and o.status = 'VALID' and o.owner = :a_object_owner
316+ ),
317+ obj_info_with_source
318+ as (select /*+ cardinality(o 10000) */o.object_owner, o.object_name, o.object_type, o.cache_stale, o.cache_id, s.line, s.text
319+ from object_cache_info o
320+ left join ]'||l_sources_view||q'[ s
321+ on s.name = o.object_name
322+ and s.type = :a_object_type
323+ and s.owner = :a_object_owner
324+ and o.cache_stale = 'Y'
325+ ),
326+ obj_info_source_grouped
327+ as (select o.object_owner, o.object_name, o.object_type, o.cache_stale, o.cache_id,
328+ cast(collect(o.text order by o.line) as ]'||l_current_schema||q'[.ut_varchar2_rows) as texts
329+ from obj_info_with_source o
330+ group by o.object_owner, o.object_type, o.object_name, o.cache_stale, cache_id
331+ order by o.object_owner, o.object_type, o.object_name
332+ )
333+ select obj
334+ from (
335+ select ]'||l_current_schema||q'[.ut_annotated_object(o.object_owner, o.object_name, o.object_type,
336+ cast(collect(
337+ ]'||l_current_schema||q'[.ut_annotation(c.annotation_position, c.annotation_name, c.annotation_text, c.subobject_name) order by c.annotation_position )
338+ as ]'||l_current_schema||q'[.ut_annotations)
339+ ) as obj
340+ from obj_info_source_grouped o
341+ join ]'||l_current_schema||q'[.ut_annotation_cache c
342+ on o.cache_id = c.cache_id
343+ where o.cache_stale = 'N'
344+ group by o.object_owner, o.object_name, o.object_type
345+ union all
346+ -- this query needs to be executed as last part of the union
347+ -- as it is updating the cache_stale flag in an autonomous transaction
348+ select value(c) as obj
349+ from table(
350+ ]'||l_current_schema||q'[.ut_annotation_parser.parse_annotations(
351+ cursor(select o.object_owner, o.object_name, o.object_type, o.cache_id, o.texts from obj_info_source_grouped o where o.cache_stale = 'Y')
352+ )
353+ ) c
354+ ) a
355+ order by a.obj.object_owner, a.obj.object_type, a.obj.object_name]';
356+ open l_cursor for l_cursor_sql using a_object_type, a_object_owner, a_object_type, a_object_owner;
357+ loop
358+ fetch l_cursor into l_obj;
359+ exit when l_cursor%notfound;
360+ pipe row (l_obj);
361+ end loop;
362+ close l_cursor;
363+ return;
364+ end;
242365
243366 function get_package_annotations(a_owner_name varchar2, a_name varchar2) return ut_annotations is
244367 l_source clob;
0 commit comments