使用DBMS_DEBUG调试PL/SQL程序
8i起, Oracle提供了DBMS_DEBUG程序包(8i之前也有), 是一种在服务器端(server-side)的调试器
它使用了一种'拉'的事件模型(a 'pull' event model), 为了调试必须建立两个数据库会话,
一个是目标会话(target session),运行要被调试的代码
另一个是调试会话(debug session), 管理目标会话
举例: 见DBMS_DEBUG: Simple example
1.开启两个会话, 会话A作为目标会话, 会话B作为调试会话
2. 会话A创建要调试的存储过程
conn a/a drop table tt; create table tt (a int, b int); insert into tt values(1,1); insert into tt values(1,2); insert into tt values(2,3); commit; create or replace procedure testproc is begin update tt set b = b*3 where a = 1; dbms_output.put_line('Rows: '|| sql%rowcount); end; / alter procedure testproc compile debug;
存储过程编译时要加上调试信息,用:
alter session set plsql_debug = true;再编译
或
alter [procedure | function | package | trigger | type]compile debug; alter [package | type] compile debug body;
3. 会话A初始化, 打开调试
------------ -- Note if serveroutput is set on in -- this session Session2 will need to -- do an additional synchronize/continue -- for testproc to return since sqlplus -- calls dbms_output.get_lines which -- will also wait to be debugged. select dbms_debug.initialize from dual; exec dbms_debug.debug_on
SQL> select dbms_debug.initialize from dual; INITIALIZE -------------------------------------------------------------------------------- 0661078B0001 SQL> exec dbms_debug.debug_on PL/SQL procedure successfully completed. SQL>注意,这个会话之前不能打开serveroutput, 否则在运行dbms_debug.debug_on这里会挂起
如果报错ORA-01031: insufficient privileges
SQL> exec :x := dbms_debug.initialize() BEGIN :x := dbms_debug.initialize(); END; * ERROR at line 1: ORA-01031: insufficient privileges ORA-06512: at "SYS.PBSDE", line 78 ORA-06512: at "SYS.DBMS_DEBUG", line 224 ORA-06512: at line 1 SQL>说明缺少"DEBUG CONNECT SESSION"权限, 加上
grant debug connect session to a;
4. 会话B设置调试参数
关联上被调试会话A
conn a/a set pages 50000 line 130 set serveroutput on size unlimited prompt Enter debug session id (from dbms_debug.initialize call): accept ssid exec dbms_debug.attach_session('&ssid')
... SQL> prompt Enter debug session id (from dbms_debug.initialize call): Enter debug session id (from dbms_debug.initialize call): SQL> accept ssid 0661078B0001 SQL> exec dbms_debug.attach_session('&ssid') PL/SQL procedure successfully completed. SQL>输入上一步得到的会话标识
在第3行设置断点
-- Set a breakpoint at line 3 (must be an -- executable statement) declare info dbms_debug.program_info; bnum binary_integer; ret binary_integer; begin info.namespace := dbms_debug.namespace_pkgspec_or_toplevel; info.name := 'TESTPROC'; info.owner := USER; info.dblink := null; info.line# := 3; ret := dbms_debug.set_breakpoint(info,3,bnum); if ret != dbms_debug.success then dbms_output.put_line('Failed to set break point'); end if; end; /
5. 会话A运行程序
exec testproc程序挂起
6. 会话B获取调试结果, 然后继续会话A,直到存储过程结束
declare info dbms_debug.runtime_info; ret binary_integer; source varchar2(4000); -- Set runtime information mask since default -- info is only info_getStackDepth + -- info_getLineInfo mask pls_integer := dbms_debug.info_getstackdepth + dbms_debug.info_getbreakpoint + dbms_debug.info_getlineinfo + dbms_debug.info_getoerinfo; -- Set breakflags to step to next executable -- statement breakflags pls_integer := dbms_debug.break_next_line; begin -- Start the interpreter ret := dbms_debug.synchronize(info,0); if ret != dbms_debug.success then dbms_output.put_line('Synchronize failed'); end if; if info.reason = dbms_debug.reason_interpreter_starting then dbms_output.put_line('Interpreter starting'); end if; -- Continue to break point ret := dbms_debug.continue(info,0,mask); if ret != dbms_debug.success then dbms_output.put_line('Continue failed'); end if; -- Output info returned dbms_output.put_line('Line is '||info.line#); if info.terminated = 1 then dbms_output.put_line('Program has terminated'); end if; dbms_output.put_line('Breakpoint # is '||info.breakpoint); dbms_output.put_line('No. of frames on stack is '||info.stackdepth); if info.reason != 3 then dbms_output.put_line('Program suspended but not for breakpoint'); end if; dbms_output.put_line('Program name is '||info.program.name); -- Find the line of code the break is on select text into source from all_source where owner = info.program.owner and name = info.program.name and line = info.line#; dbms_output.put_line('Source code is '||chr(10)||source); if info.oer != 0 then dbms_output.put_line('Exception is '||sqlerrm(info.oer)); end if; -- Step to next line and print it out ret := dbms_debug.continue(info,breakflags,mask); if ret != dbms_debug.success then dbms_output.put_line('Continue failed'); end if; dbms_output.put_line('Line is '||info.line#); select text into source from all_source where owner = info.program.owner and name = info.program.name and line = info.line#; dbms_output.put_line('Source code is '||chr(10)||source); -- Continue to end of program now ret := dbms_debug.continue(info,0,0); if ret != dbms_debug.success then dbms_output.put_line('Continue failed'); end if; end; /输出的调试结果
Interpreter starting Line is 3 Breakpoint # is 1 No. of frames on stack is 2 Program name is TESTPROC Source code is update tt Line is 6 Source code is dbms_output.put_line('Rows: '|| sql%rowcount); PL/SQL procedure successfully completed.
7. 会话A关闭调试
exec dbms_debug.debug_off挂起
8. 会话B结束调试
-- Need this since debug_off waits to be debugged -- (Enhancement Request, Bug 690796) declare info dbms_debug.runtime_info; ret binary_integer; begin ret := dbms_debug.synchronize(info,0); ret := dbms_debug.continue(info,0,0); end; /运行完synchronize,continue后,前面的会话A才能退回到SQLPLUS提示符, 这步也可以在会话A关闭调试之前操作
exec dbms_debug.detach_session最后释放与会话A的连接
外部链接:
DBMS_DEBUG
dbms_debug package - reg", version 8.1.7.0
PACKAGE DBMS_DEBUG Specification
metalink上的其它例子
DBMS_DEBUG: Simple example
DBMS_DEBUG: Simple Example When Using Scripts With SQL*Plus 8.1.7
这2个是一样的
调试匿名块:
DBMS_DEBUG: Simple Example Of Debugging An Anonymous Block
一个更好的例子在Debugging PL/SQL with DBMS_DEBUG,对DBMS_DEBUG做了一些封装
DBMS_DEBUG比较难用, 建议使用图形化的工具,如SQL Developer,PL/SQL Developer,TOAD等,进行调试
-fin
No comments:
Post a Comment