【问题标题】:How to find dependencies inside an oracle package?如何在 oracle 包中查找依赖项?
【发布时间】:2017-01-07 21:00:38
【问题描述】:

我的问题是如何通过 SQL 查询或任何其他内部/外部工具查找内部 oracle 包依赖项。甚至有可能还是我应该通过代码找出自己?

示例案例:

  • 我有一个包,其中包含 4 个过程 ABCD 和 1 个函数 F
  • A 是运行BC 过程的'main' 过程。
  • 函数FBC过程使用。
  • 过程D 是独立的(在其他地方使用)。

现在我想得到这样的结果:

STATUS      PRC/FNC NAME  PRC/FNC NAME USED INSIDE
------      ------------  ------------------------
MAIN        A             B, C
SLAVE       B             F
SLAVE       C             F
INDIVIDUAL  D             -
SLAVE       F             -

我已经在堆栈中搜索了答案,我找到的最接近的答案是:How do you programatically identify a stored procedure's dependencies? 但它只给了我包之间的依赖关系,而不是一个包“内部”的依赖关系。

【问题讨论】:

  • 你看过PL/Scope吗?
  • 我会看看,试试看,如果我是这个意思,请告诉你,谢谢。

标签: oracle plsql oracle11g plsqldeveloper


【解决方案1】:

您可以在包with PL/Scope 中获取对过程的调用,以:

alter session set plscope_settings = 'IDENTIFIERS:ALL';

如果你随后重新编译你的包,这里根据你的描述使用一个简单的大纲:

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;
/

然后您可以在user_identifiers 视图中看到各种引用。使用文档中的示例获取大纲:

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           

要获得更接近您想要的内容,您仍然需要一个分层查询来查找调用另一个的每个过程/函数的名称,因为您不感兴趣(例如)分配步骤,只是那些发生的位置。

作为一个起点,你可以这样做:

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

然后过滤叶子节点并合并调用者:

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                     

但这并没有显示F;你可以添加一个外部连接来获得它:

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                               

我很确定可以简化...

获取主/从/独立标志有点棘手;您需要确定其中每一个的含义(例如 main 有呼叫出去但没有呼叫进来;独立没有呼入或呼出;从属其他一切)可能还有进一步的加入来解决问题。

因此,这是一个起点,它可以为您提供一些信息,并希望指出要探索的内容,以便以您需要的格式获取您需要的所有信息。

【讨论】:

  • 读了半个答案后,我想“我知道是谁发的这个”……我是对的! :)
  • 一如既往的糟糕:)
猜你喜欢
  • 2012-01-01
  • 2013-03-23
  • 2015-06-27
  • 2018-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多