Vous pouvez obtenir les appels aux procédures dans un package avec PL/Scope, en commençant par :
alter session set plscope_settings = 'IDENTIFIERS:ALL';
Si vous recompilez ensuite votre package, ici en utilisant un schéma simple basé sur votre description :
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;
/
alors vous pouvez voir les différentes références dans les user_identifiers
voir. En utilisant l'exemple de la documentation pour obtenir un aperçu :
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
Pour obtenir quelque chose de plus proche de ce que vous voulez, vous avez toujours besoin d'une requête hiérarchique pour trouver le nom de chaque procédure/fonction qui en appelle une autre, puisque vous n'êtes pas intéressé par (par exemple) les étapes d'affectation, juste où elles se sont produites.
Comme point de départ, vous pourriez faire :
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
puis filtrez les nœuds feuilles et combinez les appelants :
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
Mais cela n'affiche pas F
; vous pouvez ajouter une jointure externe pour obtenir cela :
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
Je suis sûr que cela peut être simplifié...
Obtenir le drapeau principal/esclave/indépendant est un peu plus compliqué; vous devez décider ce que chacun de ces moyens signifie (par exemple, principal a des appels sortants mais pas d'appels entrants ; indépendant n'a pas d'appels entrants ou sortants ; esclave tout le reste) éventuellement avec d'autres jointures pour comprendre les choses.
Il s'agit donc d'un point de départ qui vous fournit certaines des informations et, espérons-le, indique les éléments à explorer pour obtenir toutes les informations dont vous avez besoin, dans le format dont vous avez besoin.