Sie können die Aufrufe von Prozeduren innerhalb eines Pakets mit PL/Scope erhalten, beginnend mit:
alter session set plscope_settings = 'IDENTIFIERS:ALL';
Wenn Sie dann Ihr Paket neu kompilieren, hier mit einer einfachen Gliederung basierend auf Ihrer Beschreibung:
create or replace package p42 as
procedure a;
procedure b;
procedure c;
procedure d;
function f return number;
end p42;
/
create or replace package body p42 as
procedure a is
begin
b;
c;
end a;
procedure b is
n number;
begin
n := f;
end b;
procedure c is
n number;
begin
n := f;
end c;
procedure d is
begin
null;
end d;
function f return number is
begin
return 42;
end f;
end p42;
/
dann können Sie die verschiedenen Referenzen in den user_identifiers
sehen Aussicht. Verwenden Sie das Beispiel aus der Dokumentation, um eine Gliederung zu erhalten:
WITH v AS (
SELECT Line,
Col,
INITCAP(NAME) Name,
LOWER(TYPE) Type,
LOWER(USAGE) Usage,
USAGE_ID,
USAGE_CONTEXT_ID
FROM USER_IDENTIFIERS
WHERE Object_Name = 'P42'
AND Object_Type = 'PACKAGE BODY'
)
SELECT RPAD(LPAD(' ', 2*(Level-1)) ||
Name, 20, '.')||' '||
RPAD(Type, 20)||
RPAD(Usage, 20)
IDENTIFIER_USAGE_CONTEXTS
FROM v
START WITH USAGE_CONTEXT_ID = 0
CONNECT BY PRIOR USAGE_ID = USAGE_CONTEXT_ID
ORDER SIBLINGS BY Line, Col
/
IDENTIFIER_USAGE_CONTEXTS
-------------------------------------------------------------
P42................. package definition
A................. procedure definition
B............... procedure call
C............... procedure call
B................. procedure definition
N............... variable declaration
Number........ number datatype reference
N............... variable assignment
F............. function call
C................. procedure definition
N............... variable declaration
Number........ number datatype reference
N............... variable assignment
F............. function call
D................. procedure definition
F................. function definition
Number.......... number datatype reference
Um dem, was Sie wollen, etwas näher zu kommen, benötigen Sie immer noch eine hierarchische Abfrage, um den Namen jeder Prozedur/Funktion zu finden, die eine andere aufruft, da Sie (zum Beispiel) nicht an den Zuweisungsschritten interessiert sind, sondern nur daran, wo diese passiert sind.
Als Ausgangspunkt könnten Sie Folgendes tun:
select *
from (
select name, type, connect_by_root(name) as root_name,
connect_by_root(type) as root_type, connect_by_isleaf as isleaf
from user_identifiers
start with object_type = 'PACKAGE BODY'
and object_name = 'P42'
and type in ('FUNCTION', 'PROCEDURE')
and usage = 'DEFINITION'
connect by object_type = prior object_type
and object_name = prior object_name
and usage_context_id = prior usage_id
)
where type in ('FUNCTION', 'PROCEDURE');
NAME TYPE ROOT_NAME ROOT_TYPE ISLEAF
---- ------------------ --------- --------- ----------
A PROCEDURE A PROCEDURE 0
B PROCEDURE A PROCEDURE 1
C PROCEDURE A PROCEDURE 1
B PROCEDURE B PROCEDURE 0
F FUNCTION B PROCEDURE 1
C PROCEDURE C PROCEDURE 0
F FUNCTION C PROCEDURE 1
D PROCEDURE D PROCEDURE 1
F FUNCTION F FUNCTION 0
Filtern Sie dann die Blattknoten und kombinieren Sie die Aufrufer:
select root_name, root_type,
listagg(case when name = root_name then null else name end, ', ')
within group (order by name) as callers
from (
select name, type, connect_by_root(name) as root_name,
connect_by_root(type) as root_type, connect_by_isleaf as isleaf
from user_identifiers
start with object_type = 'PACKAGE BODY'
and object_name = 'P42'
and type in ('FUNCTION', 'PROCEDURE')
and usage = 'DEFINITION'
connect by object_type = prior object_type
and object_name = prior object_name
and usage_context_id = prior usage_id
)
where type in ('FUNCTION', 'PROCEDURE')
and isleaf = 1
group by root_name, root_type;
ROOT_NAME ROOT_TYPE CALLERS
--------- --------- --------------------
A PROCEDURE B, C
B PROCEDURE F
C PROCEDURE F
D PROCEDURE
Aber das zeigt nicht F
; Sie können einen äußeren Join hinzufügen, um dies zu erhalten:
with ui as (
select * from user_identifiers
where object_type = 'PACKAGE BODY'
and object_name = 'P42'
),
calls as (
select object_type, object_name, name, type, signature,
connect_by_root(name) as root_name,
connect_by_root(type) as root_type,
connect_by_root(signature) as root_signature,
connect_by_isleaf as isleaf
from ui
start with type in ('FUNCTION', 'PROCEDURE')
and usage = 'DEFINITION'
connect by usage_context_id = prior usage_id
and prior usage != 'CALL'
)
select ui.name, ui.type,
listagg(case when c.name = c.root_name then null else c.name end, ', ')
within group (order by c.name) as callers
from ui
left join calls c on c.object_type = ui.object_type
and c.object_name = ui.object_name
and c.root_type = ui.type
and c.root_name = ui.name
and c.root_signature = ui.signature
and c.type in ('FUNCTION', 'PROCEDURE')
and c.isleaf = 1
where ui.type in ('FUNCTION', 'PROCEDURE')
and ui.usage = 'DEFINITION'
group by ui.name, ui.type;
NAME TYPE CALLERS
---- ------------------ --------------------
A PROCEDURE B, C
B PROCEDURE F
C PROCEDURE F
D PROCEDURE
F FUNCTION
Ich bin mir ziemlich sicher, dass das vereinfacht werden kann...
Das Main/Slave/Independent-Flag zu bekommen ist etwas kniffliger; Sie müssen entscheiden, was jede dieser Bedeutungen bedeutet (z. B. Main hat ausgehende Anrufe, aber keine eingehenden Anrufe; Independent hat keine eingehenden oder ausgehenden Anrufe; Slave alles andere), möglicherweise mit weiteren Joins, um die Dinge herauszufinden.
Dies ist also ein Ausgangspunkt, der Ihnen einige der Informationen liefert und hoffentlich auf Dinge hinweist, die Sie erkunden können, um alle Informationen zu erhalten, die Sie benötigen, in dem Format, in dem Sie sie benötigen.