D
Did you ever wonder which lines in you package are used by which procedure/function? Let's find package modules (procedures and functions) and their boundaries (starting and ending lines).
WITH x AS (
SELECT
'&OBJECT_NAME' AS object_name,
'PACKAGE BODY' AS object_type
FROM DUAL
),
s AS (
SELECT s.line, s.text
FROM user_source s
CROSS JOIN x
WHERE s.name = x.object_name
AND s.type = x.object_type
--AND NOT REGEXP_LIKE(s.text, '^(\s)*$') -- strip empty line
--AND NOT REGEXP_LIKE(s.text, '^(\s)[-]{2}') -- strip comments
),
p AS (
-- to find first and last module line
SELECT
ROW_NUMBER() OVER (PARTITION BY NULL ORDER BY i.line) AS position,
i.name,
i.type,
i.line AS start_line,
LEAD(i.line) OVER (PARTITION BY i.object_name, i.object_type ORDER BY i.line) - 1 AS end_line
FROM user_identifiers i
CROSS JOIN x
WHERE i.object_name = x.object_name
AND i.object_type = x.object_type
AND i.type IN ('PROCEDURE', 'FUNCTION')
AND i.usage = 'DEFINITION'
ORDER BY line
),
s1 AS (
-- to find multiline comments before each module
SELECT s.*, ROW_NUMBER() OVER(ORDER BY s.line) AS rn
FROM s
WHERE REGEXP_LIKE(s.text, '(/\*)', 'i')
AND NOT REGEXP_LIKE(s.text, '(\*/)', 'i')
),
s2 AS (
SELECT s.*, ROW_NUMBER() OVER(ORDER BY s.line) AS rn
FROM s
WHERE NOT REGEXP_LIKE(s.text, '(/\*)', 'i')
AND REGEXP_LIKE(s.text, '(\*/)', 'i')
)
SELECT
r.position,
r.name,
r.type,
r.start_line,
r.end_line,
r.lines,
m.start_line AS description_start
FROM (
SELECT
p.position,
p.name,
p.type,
p.start_line,
MAX(s.line) AS end_line,
MAX(s.line) - p.start_line AS lines
FROM (
-- find last END; before next module start
SELECT
p.position, p.name, p.type,
p.start_line,
NVL(LEAD(p.start_line) OVER (ORDER BY p.start_line), MAX((SELECT MAX(s.line) - 1 AS last_line FROM s))) AS next_module
FROM p
GROUP BY p.position, p.name, p.type, p.start_line
) p
LEFT JOIN s
ON s.line > p.start_line
AND s.line < p.next_module
AND REGEXP_LIKE(UPPER(s.text), '^\s*END(\s+' || p.name || ')?\s*;', 'i')
GROUP BY p.position, p.name, p.type, p.start_line
) r
LEFT JOIN (
SELECT s1.line AS start_line, s2.line AS end_line
FROM s1
LEFT JOIN s2 ON s2.rn = s1.rn
) m ON m.end_line = r.start_line - 1
ORDER BY r.position;
To get assess to PL/SQL scope, you need to recompile objects with IDENTIFIERS:ALL.
BEGIN
recompile (
in_optimize => 1,
in_code_type => 'INTERPRETED',
in_scope => 'IDENTIFIERS:ALL, STATEMENTS:ALL',
in_invalid_only => FALSE
);
END;
/
Comments
Post a Comment