Du kan få anropen till procedurer inom ett paket med PL/Scope, som börjar med:
alter session set plscope_settings = 'IDENTIFIERS:ALL';
Om du sedan kompilerar om ditt paket, här med en enkel disposition baserat på din beskrivning:
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;
/
sedan kan du se de olika referenserna i user_identifiers
se. Använd exemplet från dokumentationen för att få en disposition:
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
För att komma något närmare det du vill behöver du fortfarande en hierarkisk fråga för att hitta namnet på varje procedur/funktion som anropar en annan, eftersom du inte är intresserad av (till exempel) tilldelningsstegen, bara var de hände.
Som utgångspunkt kan du göra:
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
filtrera sedan lövnoderna och kombinera anroparna:
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
Men det visar inte F
; du kan lägga till en yttre koppling för att få det:
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
Jag är ganska säker på att det går att förenkla...
Det är lite knepigare att få tag på huvud/slav/oberoende flagga; du måste bestämma vad var och en av dessa betyder (t.ex. main har samtal som går ut men inga samtal kommer in; oberoende har inga samtal in eller ut; slave allt annat) eventuellt med ytterligare sammankopplingar för att ta reda på saker och ting.
Så det här är en utgångspunkt som ger dig en del av informationen och förhoppningsvis pekar på saker att utforska för att få all information du behöver, i det format du behöver.