确定 PL/SQL 过程的调用层次结构
Posted
技术标签:
【中文标题】确定 PL/SQL 过程的调用层次结构【英文标题】:Determining call hierarchy of PL/SQL procedure 【发布时间】:2015-02-06 20:58:02 【问题描述】:我正在处理一些旧的 PL/SQL 代码,我想显示调用层次结构,就像在 Eclipse 和 Java 代码中一样。
例如,如果我有以下代码:
create or replace package body pkgA as
procedure foobar is begin
lambda(1);
end;
procedure lambda(a NUMBER) is begin
pkgB.test();
end;
end pkgA;
/
create or replace package body pkgB as
procedure test is begin
select 1 from dual;
end;
end pkgB;
/
我想要这棵树:
pkgB.test
pkgA.lambda
pkgA.foobar
注意:我使用的是 Toad 9,但我没有看到这样的功能(好吧,除非我需要寻找外键的引用树之类的东西)。
此外,我更多的是寻找静态分析而不是动态分析,或者暗示我执行代码的东西。
【问题讨论】:
PL/SQL 很可能会错过这样的工具。请尝试PL/SQL Hierarchical Profiler。你必须执行代码。 PL/Scope 可以做到这一点。我现在没有时间创建一个具体的例子,也许其他人可以。 关于 PL/Scope 的信息 read this article. DBMS_DEBUG.PRINT_BACKTRACE 您可以在需要堆栈跟踪的程序单元中使用dbms_utility.format_Call_stack 【参考方案1】:我认为更好的打包过程是:dbms_utility.format_error_backtrace
所以你会使用 DBMS_OUTPUT.PUT_LINE(dbms_utility.format_error_backtrace); 我将它们放在我的异常处理程序中以一直进行测试(直到我有一个代码模板将其放入其中)。我也输出指令:
所以它返回如下结果:
EXCEPTION IN aeo_misc_tools.cursor_to_listV2 - -900: ORA-00900: invalid SQL statement
EXCEPTION IN my test script - -900: ORA-00900: invalid SQL statement
Error stack at top level:
ORA-06512: at "AEO.AEO_MISC_TOOLS", line 805
ORA-06512: at line 8
它不会按照您的指定将错误格式化为树格式,但它会完成工作,以便您可以在正确的行上找到错误。
【讨论】:
这不是一个完整的解决方案,如果可以完全自动完成就太好了。想象一下,您面对的是一个血腥的企业遗留代码,其中一个包由 60k 行 plsql 代码组成。 貌似UTL_CALL_STACK
灵活一点,oracle-base.com/articles/12c/utl-call-stack-12cr1有很好的概述
@MarkStewart - 感谢您的链接,但实际上我从该文章中引用的 UTL_CALL_STACK 例程中看到的有用输出比从 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE 中看到的要少。文章示例显示您应该看到所有调用级别,但我只看到第一个和最后一个。其他例子给了我类似的,有限的结果。我确认了我们的版本,但不知道为什么我看到的更少。【参考方案2】:
您可以使用Visual-Expert的调用层次结构,该工具分析PL代码并向您显示调用函数
【讨论】:
【参考方案3】:这可能不是最好的解决方案,但我已经通过递归使用 PL/Scope 找到了答案。希望它可以帮助任何有需要的人。 :)
create or replace procedure getAllChildCall ( definitionName in char, packageName in char, callLevel in number )
as
begin
for rec in (
with package_tree as (
select * from all_identifiers
where object_name = packageName and object_type = 'PACKAGE BODY'
)
select distinct
name, signature, type, line,
usage, usage_id, usage_context_id
from package_tree
start with (name = definitionName and usage = 'DEFINITION')
connect by prior usage_id = usage_context_id
) loop
if rec.usage = 'CALL' and rec.name not in (
'DEBUG', 'SQLERRM', 'COMMITRECORD', 'ISNOTZERO', 'NVL', 'TRUNC', 'ROUND') then
dbms_output.put_line(LPAD(' ', 2*callLevel, ' ') || rec.name);
getallchildcall(rec.name, packageName, callLevel+1);
end if;
end loop;
end;
/
set serveroutput on
declare
callLevel number;
begin
callLevel := 1;
dbms_output.put_line('start traverse the package child call graph...');
getAllChildCall(upper('YOUR_PROCEDURE_NAME'), upper('YOUR_PACKAGE_NAME'), callLevel);
end;
【讨论】:
以上是关于确定 PL/SQL 过程的调用层次结构的主要内容,如果未能解决你的问题,请参考以下文章
如何确定通用 PL/SQL 过程的参数(执行 group by 子句)?
带有 PL SQL 表类型参数的 Oracle 存储过程的 JDBC 调用