Oracle8i Supplied Packages Reference Release 8.1.5 A68001-01 |
|
DBMS_DEBUG
is a PL/SQL API to the PL/SQL debugger layer, Probe, in the Oracle server.
This API is primarily intended to implement server-side debuggers, and it provides a way to debug server-side PL/SQL program units.
In order to debug server-side code, it is necessary to have two database sessions: one session to run the code in debug-mode (the target session), and a second session to supervise the target session (the debug session).
The target session becomes available for debugging by making initializing calls with DBMS_DEBUG
. This marks the session, so that the PL/SQL interpreter runs in debug-mode and generates debug events. As debug events are generated, they are posted from the session. In most cases, debug events require return notification: the interpreter pauses awaiting a reply.
Meanwhile, the debug session must also initialize itself using DBMS_DEBUG
: This tells it what target session to supervise. The debug session may then call entrypoints in DBMS_DEBUG
to read events which were posted from the target session and to communicate with the target session.
See Also:
Figure 7-1 and Figure 7-2 illustrate the flow of operations in the session to be debugged and in the debugging session. |
DBMS_DEBUG
does not provide any interface to the PL/SQL compiler; however, it does depend on debug information optionally generated by the compiler. Without debug information, it is not possible to look at or modify the values of parameters or variables. There are two ways to ensure that debug information is generated: through a session switch, or through individual recompilation.
To set the session switch, enter the following statement:
ALTER SESSION SET PLSQL_DEBUG = true;
This instructs the compiler to generate debug information for the remainder of the session. It does not recompile any existing PL/SQL.
To generate debug information for existing PL/SQL code, use one of the following statements (the second recompiles a package or type body):
ALTER [PROCEDURE | FUNCTION | PACKAGE | TRIGGER | TYPE] <name> COMPILE DEBUG; ALTER [PACKAGE | TYPE] <name> COMPILE DEBUG BODY;
The interpreter pauses execution at the following times:
DBMS_DEBUG
.CONTINUE
in the breakflags
parameter.
There is no event for session termination. Therefore, it is the responsibility of the debug session to check and make sure that the target session has not ended. A call to DBMS_DEBUG
.SYNCHRONIZE
after the target session has ended causes the debug session to hang until it times out.
The diagram suggests that it is possible to set breakpoints prior to having a target session. This is true. In this case, Probe caches the breakpoint request and transmits it to the target session at first synchronization. However, if a breakpoint request is deferred in this fashion, then:
SET_BREAKPOINT
does not set the breakpoint number (it can be obtained later from SHOW_BREAKPOINTS
if necessary).
SET_BREAKPOINT
does not validate the breakpoint request. If the requested source line does not exist, then an error silently occurs at synchronization, and no breakpoint is set.
To debug Probe, there are diagnostics parameters to some of the calls in DBMS_DEBUG
. These parameters specify whether to place diagnostic output in the RDBMS tracefile. If output to the RDBMS tracefile is disabled, then these parameters have no effect.
This type specifies a program location. It is a line number in a program unit.This is used for stack backtraces and for setting and examining breakpoints.The read-only fields are currently ignored by Probe for breakpoint operations. They are set by Probe only for stack backtraces.
EntrypointName |
Null, unless this is a nested procedure or function. |
LibunitType |
Disambiguate among objects that share the same namespace (for example, procedure and package specifications). See the Libunit Types for more information. |
TYPE program_info IS RECORD ( -- The following fields are used when setting a breakpoint Namespace BINARY_INTEGER, -- See 'NAMESPACES' section below. Name VARCHAR2(30), -- name of the program unit Owner VARCHAR2(30), -- owner of the program unit Dblink VARCHAR2(30), -- database link, if remote Line# BINARY_INTEGER, -- Read-only fields (set by Probe when doing a stack backtrace) LibunitType BINARY_INTEGER, EntrypointName VARCHAR2(30) );
This type gives context information about the running program.
TYPE runtime_info IS RECORD ( Line# BINARY_INTEGER, -- (duplicate of program.line#) Terminated BINARY_INTEGER, -- has the program terminated? Breakpoint BINARY_INTEGER, -- breakpoint number StackDepth BINARY_INTEGER, -- number of frames on the stack InterpreterDepth BINARY_INTEGER, -- <reserved field> Reason BINARY_INTEGER, -- reason for suspension Program program_info -- source location );
This type gives information about a breakpoint, such as its current status and the program unit in which it was placed.
TYPE breakpoint_info IS RECORD ( -- These fields are duplicates of 'program_info': Name VARCHAR2(30), Owner VARCHAR2(30), DbLink VARCHAR2(30), Line# BINARY_INTEGER, LibunitType BINARY_INTEGER, Status BINARY_INTEGER -- see breakpoint_status_* below );
This type is used by GET_INDEXES
to return the available indexes for an indexed table.
TYPE index_table IS table of BINARY_INTEGER INDEX BY BINARY_INTEGER;
This type is used by PRINT_BACKTRACE
.
TYPE backtrace_table IS TABLE OF program_info INDEX BY BINARY_INTEGER;
This type is used by SHOW_BREAKPOINTS
.
TYPE breakpoint_table IS TABLE OF breakpoint_info INDEX BY BINARY_INTEGER;
This type is used by SHOW_SOURCE
.
TYPE vc2_table IS TABLE OF VARCHAR2(90) INDEX BY BINARY_INTEGER;
A breakpoint status may have these values:
breakpoint_status_unused |
Breakpoint is not in use. |
Otherwise, the status is a mask of the following values:
Program units on the server reside in different namespaces.When setting a breakpoint, it is necessary to specify the desired namespace.
Namespace_cursor
contains cursors (anonymous blocks).
Namespace_pgkspec_or_toplevel
contains:
Namespace_pkg_body
contains package bodies and type bodies.
Namespace_trigger
contains triggers.
These values are used to disambiguate among objects in a given namespace. These constants are used in PROGRAM_INFO
when Probe is giving a stack backtrace.
LibunitType_cursor |
|
LibunitType_procedure |
|
LibunitType_function |
|
LibunitType_package |
|
LibunitType_package_body |
|
LibunitType_trigger |
|
LibunitType_Unknown |
|
These are values to use for the breakflags
parameter to CONTINUE
, in order to tell Probe what events are of interest to the client. These flags may be combined.
These are flags which may be passed as the info_requested
parameter to SYNCHRONIZE
, CONTINUE
, and GET_RUNTIME_INFO
.
info_getStackDepth |
Get the current depth of the stack. |
info_getBreakpoint |
Get the breakpoint number. |
info_getLineinfo |
Get program unit information. |
After CONTINUE
is run, the program either runs to completion or breaks on some line.
These values are returned by the various functions called in the debug session (SYNCHRONIZE
, CONTINUE
, SET_BREAKPOINT
, and so on). If PL/SQL exceptions worked across client/server and server/server boundaries, then these would all be exceptions rather than error codes.
success |
Normal termination. |
Statuses returned by GET_VALUE
and SET_VALUE
:
Statuses returned by SET_VALUE
:
Statuses returned by the breakpoint functions:
General error codes (returned by many of the DBMS_DEBUG
subprograms):
illegal_init |
|
The following exceptions are raised by procedure SELF_CHECK
:
default_timeout |
The timeout value (used by both sessions).The smallest possible timeout is 1 second. If this value is set to 0, then a large value (3600) is used. |
Subprogram | Description |
---|---|
PROBE_VERSION procedure |
Returns the version number of |
SELF_CHECK procedure |
Performs an internal consistency check. |
SET_TIMEOUT function |
Sets the timeout value. |
INITIALIZE function |
Sets debugID in target session. |
DEBUG_ON procedure |
Turns debug-mode on. |
DEBUG_OFF procedure |
Turns debug-mode off. |
ATTACH_SESSION procedure |
Notifies the debug session about the target debugID. |
SYNCHRONIZE function |
Waits for program to start running. |
SHOW_SOURCE procedure |
Fetches program source. |
PRINT_BACKTRACE procedure |
Prints a stack backtrace. |
CONTINUE function |
Continues execution of the target program. |
SET_BREAKPOINT function |
Sets a breakpoint in a program unit. |
DELETE_BREAKPOINT function |
Deletes a breakpoint. |
DISABLE_BREAKPOINT function |
Disables a breakpoint. |
ENABLE_BREAKPOINT function |
Activates an existing breakpoint. |
SHOW_BREAKPOINTS procedure |
Returns a listing of the current breakpoints. |
GET_VALUE function |
Gets a value from the currently-running program. |
SET_VALUE function |
Sets a value in the currently-running program. |
DETACH_SESSION procedure |
Stops debugging the target program. |
GET_RUNTIME_INFO function |
Returns information about the current program. |
GET_INDEXES function |
Returns the set of indexes for an indexed table. |
EXECUTE procedure |
Executes SQL or PL/SQL in the target session. |
These following subprograms may be called in either the target or the debug session:
This procedure returns the version number of DBMS_DEBUG
on the server.
DBMS_DEBUG.PROBE_VERSION ( major out BINARY_INTEGER, minor out BINARY_INTEGER);
Parameter | Description |
---|---|
major |
Major version number. |
minor |
Minor version number: increments as functionality is added. |
This procedure performs an internal consistency check. SELF_CHECK
also runs a communications test to ensure that the Probe processes are able to communicate.
If SELF_CHECK
does not return successfully, then an incorrect version of DBMS_DEBUG
was probably installed on this server. The solution is to install the correct version (pbload
.sql
loads DBMS_DEBUG
and the other relevant packages).
DBMS_DEBUG.SELF_CHECK ( timeout IN binary_integer := 60);
Parameter | Description |
---|---|
timeout |
The timeout to use for the communication test. Default is 60 seconds. |
All of these exceptions are fatal. They indicate a serious problem with Probe that prevents it from working correctly.
This function sets the timeout value and returns the new timeout value.
DBMS_DEBUG.SET_TIMEOUT ( timeout BINARY_INTEGER) RETURN BINARY_INTEGER;
Parameter | Description |
---|---|
timeout |
The timeout to use for communication between the target and debug sessions. |
The following subprograms are run in the target session (the session that is to be debugged):
This function initializes the target session for debugging.
DBMS_DEBUG.INITIALIZE ( debug_session_id IN VARCHAR2 := NULL, diagnostics IN BINARY_INTEGER := 0) RETURN VARCHAR2;
Parameter | Description |
---|---|
debug_session_id |
Name of session ID. If |
diagnostics |
Indicates whether to dump diagnostic output to the tracefile. 1 = print diagnostics |
The newly-registered debug session ID (debugID)
This procedure marks the target session so that all PL/SQL is run in debug mode. This must be done before any debugging can take place.
DBMS_DEBUG.DEBUG_ON ( no_client_side_plsql_engine BOOLEAN := TRUE, immediate BOOLEAN := FALSE);
This procedure notifies the target session that debugging should no longer take place in that session. It is not necessary to call this function before ending the session.
DBMS_DEBUG.DEBUG_OFF;
None.
The server does not handle this entrypoint specially. Therefore, it attempts to debug this entrypoint.
The following subprograms should be run in the debug session only:
This procedure notifies the debug session about the target program.
DBMS_DEBUG.ATTACH_SESSION ( debug_session_id IN VARCHAR2, diagnostics IN BINARY_INTEGER := 0);
Parameter | Description |
---|---|
debug_session_id |
Debug ID from a call to |
diagnostics |
Generate diagnostic output if non-zero. |
This function waits until the target program signals an event. If info_requested
is not NULL
, then it calls GET_RUNTIME_INFO
.
DBMS_DEBUG.SYNCHRONIZE ( run_info OUT runtime_info, info_requested IN BINARY_INTEGER := NULL) RETURN BINARY_INTEGER;
Parameter | Description |
---|---|
run_info |
Structure in which to write information about the program. By default, this includes information about what program is running and at which line execution has paused. |
info_requested |
Optional bit-field in which to request information other than the default (which is See "Information Flags". |
Return | Description |
---|---|
success |
|
error_timeout |
Timed out before the program started execution. |
error_communication |
Other communication error. |
The best way to get the source code (for a program that is being run) is to use SQL. For example:
DECLARE info DBMS_DEBUG.runtime_info; BEGIN -- call DBMS_DEBUG.SYNCHRONIZE, CONTINUE, -- or GET_RUNTIME_INFO to fill in 'info' SELECT text INTO <buffer> FROM all_source WHERE owner = info.Program.Owner AND name = info.Program.Name AND line = info.Line#; END;
However, this does not work for non-persistent programs (for example, anonymous blocks and trigger invocation blocks). For non-persistent programs, call SHOW_SOURCE
. There are two flavors: one returns an indexed table of source lines, and the other returns a packed (and formatted) buffer.
There are two overloaded SHOW_SOURCE
procedures.
DBMS_DEBUG.SHOW_SOURCE ( first_line IN BINARY_INTEGER, last_line IN BINARY_INTEGER, source OUT vc2_table);
An indexed table of source-lines. The source lines are stored starting at first_line
. If any error occurs, then the table is empty.
This second overloading of SHOW_SOURCE
returns the source in a formatted buffer, complete with line-numbers. It is faster than the indexed table version, but it does not guarantee to fetch all the source.
If the source does not fit in bufferlength (buflen
), then additional pieces can be retrieved using the GET_MORE_SOURCE
procedure (pieces
returns the number of additional pieces that need to be retrieved).
DBMS_DEBUG.SHOW_SOURCE ( first_line IN BINARY_INTEGER, last_line IN BINARY_INTEGER, window IN BINARY_INTEGER, print_arrow IN BINARY_INTEGER, buffer IN OUT VARCHAR2, buflen IN BINARY_INTEGER, pieces OUT BINARY_INTEGER);
This procedure prints a backtrace listing of the current execution stack. This should only be called if a program is currently running.
There are two overloaded PRINT_BACKTRACE
procedures.
DBMS_DEBUG.PRINT_BACKTRACE ( listing IN OUT VARCHAR2);
Parameter | Description |
---|---|
listing |
A formatted character buffer with embedded newlines. |
DBMS_DEBUG.PRINT_BACKTRACE ( backtrace OUT backtrace_table);
This function passes the given breakflags (a mask of the events that are of interest) to Probe in the target process. It tells Probe to continue execution of the target process, and it waits until the target process runs to completion or signals an event.
If info_requested
is not NULL
, then calls GET_RUNTIME_INFO
.
DBMS_DEBUG.CONTINUE ( run_info IN OUT runtime_info, breakflags IN BINARY_INTEGER, info_requested IN BINARY_INTEGER := NULL) RETURN BINARY_INTEGER;
Parameter | Description |
---|---|
run_info |
Information about the state of the program. |
breakflags |
Mask of events that are of interest. See "Breakflags" . |
info_requested |
Which information should be returned in |
Return | Description |
---|---|
success |
|
error_timeout |
Timed out before the program started running. |
error_communication |
Other communication error. |
This function sets a breakpoint in a program unit, which persists for the current session. Execution pauses if the target program reaches the breakpoint.
DBMS_DEBUG.SET_BREAKPOINT ( program IN program_info, line# IN BINARY_INTEGER, breakpoint# OUT BINARY_INTEGER, fuzzy IN BINARY_INTEGER := 0, iterations IN BINARY_INTEGER := 0) RETURN BINARY_INTEGER;
Return | Description |
---|---|
success |
|
error_illegal_line |
Cannot set a breakpoint at that line. |
error_bad_handle |
No such program unit exists. |
This function deletes a breakpoint.
DBMS_DEBUG.DELETE_BREAKPOINT ( breakpoint IN BINARY_INTEGER) RETURN BINARY_INTEGER;
Parameter | Description |
---|---|
breakpoint |
Breakpoint number from a previous call to |
This function makes an existing breakpoint inactive, but it leaves it in place.
DBMS_DEBUG.DISABLE_BREAKPOINT ( breakpoint IN BINARY_INTEGER) RETURN BINARY_INTEGER;
Parameter | Description |
---|---|
breakpoint |
Breakpoint number from a previous call to |
Returns | Description |
---|---|
success |
|
error_no_such_breakpt |
No such breakpoint exists. |
error_idle_breakpt |
Cannot disable an unused breakpoint. |
This function is the reverse of disabling. This enables a previously disabled breakpoint.
DBMS_DEBUG.ENABLE_BREAKPOINT ( breakpoint IN BINARY_INTEGER) RETURN BINARY_INTEGER;
Parameter | Description |
---|---|
breakpoint |
Breakpoint number from a previous call to |
Return | Description |
---|---|
success |
|
error_no_such_breakpt |
No such breakpoint exists. |
error_idle_breakpt |
Cannot enable an unused breakpoint. |
This procedure returns a listing of the current breakpoints. There are two overloaded SHOW_BREAKPOINTS
procedures.
DBMS_DEBUG.SHOW_BREAKPOINTS ( listing IN OUT VARCHAR2);
Parameter | Description |
---|---|
listing |
A formatted buffer (including newlines) of the breakpoints. |
DBMS_DEBUG.SHOW_BREAKPOINTS ( listing OUT breakpoint_table);
Parameter | Description |
---|---|
listing |
Indexed table of breakpoint entries. The breakpoint number is indicated by the index into the table. Breakpoint numbers start at 1 and are reused when deleted. |
This function gets a value from the currently-running program. There are two overloaded GET_VALUE
functions.
DBMS_DEBUG.GET_VALUE ( variable_name IN VARCHAR2, frame# IN BINARY_INTEGER, scalar_value OUT VARCHAR2, format IN VARCHAR2 := NULL) RETURN BINARY_INTEGER;
This form of GET_VALUE
is for fetching package variables. Instead of a frame#, it takes a handle, which describes the package containing the variable.
DBMS_DEBUG.GET_VALUE ( variable_name IN VARCHAR2, handle IN program_info, scalar_value OUT VARCHAR2, format IN VARCHAR2 := NULL) RETURN BINARY_INTEGER;
This example illustrates how to get the value with a given package PACK
in schema SCOTT
, containing variable VAR
:
DECLARE handle dbms_debug.program_info; resultbuf VARCHAR2(500); retval BINARY_INTEGER; BEGIN handle.Owner := 'SCOTT'; handle.Name := 'PACK'; handle.namespace := dbms_debug.namespace_pkgspec_or_toplevel; retval := dbms_debug.get_value('VAR', handle, resultbuf, NULL); END;
This function sets a value in the currently-running program. There are two overloaded SET_VALUE
functions.
DBMS_DEBUG.SET_VALUE ( frame# IN binary_integer, assignment_statement IN varchar2) RETURN BINARY_INTEGER;
This form of SET_VALUE
sets the value of a package variable.
DBMS_DEBUG.SET_VALUE ( handle IN program_info, assignment_statement IN VARCHAR2) RETURN BINARY_INTEGER;
Return | Description |
---|---|
error_no_such_object |
- Package is not instantiated. - User does not have privileges to debug the package. - Object does not exist in the package. |
In some cases, the PL/SQL compiler uses temporaries to access package variables, and Probe does not guarantee to update such temporaries. It is possible, although unlikely, that modification to a package variable using SET_VALUE
might not take effect for a line or two.
To set the value of SCOTT
.PACK
.var
to 6:
DECLARE handle dbms_debug.program_info; retval BINARY_INTEGER; BEGIN handle.Owner := 'SCOTT'; handle.Name := 'PACK'; handle.namespace := dbms_debug.namespace_pkgspec_or_toplevel; retval := dbms_debug.set_value(handle, 'var := 6;'); END;
This procedure stops debugging the target program. This procedure may be called at any time, but it does not notify the target session that the debug session is detaching itself, and it does not abort execution of the target session. Therefore, care should be taken to ensure that the target session does not hang itself.
DBMS_DEBUG.DETACH_SESSION;
None.
This function returns information about the current program. It is only needed if the info_requested
parameter to SYNCHRONIZE
or CONTINUE
was set to 0
.
DBMS_DEBUG.GET_RUNTIME_INFO ( info_requested IN BINARY_INTEGER, run_info OUT runtime_info) RETURN BINARY_INTEGER;
Parameter | Description |
---|---|
info_requested |
Which information should be returned in |
run_info |
Information about the state of the program. |
Given a name of a variable or parameter, this function returns the set of its indexes, if it is an indexed table. An error is returned if it is not an indexed table.
DBMS_DEBUG.GET_INDEXES ( varname IN VARCHAR2, frame# IN BINARY_INTEGER, handle IN program_info, entries OUT index_table) RETURN BINARY_INTEGER;
Return | Description |
---|---|
error_no_such_object |
- The package is not instantiated. - The user does not have privileges to debug the package. - The object does not exist in the package. |
This procedure executes SQL or PL/SQL code in the target session. The target session is assumed to be waiting at a breakpoint (or other event). The call to DBMS_DEBUG
.EXECUTE
occurs in the debug session, which then asks the target session to execute the code.
DBMS_DEBUG.EXECUTE ( what IN VARCHAR2, frame# IN BINARY_INTEGER, bind_results IN BINARY_INTEGER, results IN OUT NOCOPY dbms_debug_vc2coll, errm IN OUT NOCOPY VARCHAR2);
This example executes a SQL statement. It returns no results.
DECLARE coll sys.dbms_debug_vc2coll; -- results (unused) errm VARCHAR2(100); BEGIN dbms_debug.execute('insert into emp(ename,empno,deptno) ' || 'values(''LJE'', 1, 1)', -1, 0, coll, errm); END;
This example executes a PL/SQL block, and it returns no results. The block is an autonomous transaction, which means that the value inserted into the table becomes visible in the debug session.
DECLARE coll sys.dbms_debug_vc2coll; errm VARCHAR2(100); BEGIN dbms_debug.execute( 'DECLARE PRAGMA autonomous_transaction; ' || 'BEGIN ' || ' insert into emp(ename, empno, deptno) ' || ' values(''LJE'', 1, 1); ' || ' COMMIT; ' || 'END;', -1, 0, coll, errm); END;
This example executes a PL/SQL block, and it returns some results.
DECLARE coll sys.dbms_debug_vc2coll; errm VARCHAR2(100); BEGIN dbms_debug.execute( 'DECLARE ' || ' pp SYS.dbms_debug_vc2coll := SYS.dbms_debug_vc2coll(); ' || ' x PLS_INTEGER; ' || ' i PLS_INTEGER := 1; ' || 'BEGIN ' || ' SELECT COUNT(*) INTO x FROM emp; ' || ' pp.EXTEND(x * 6); ' || ' FOR c IN (SELECT * FROM emp) LOOP ' || ' pp(i) := ''Ename: '' || c.ename; i := i+1; ' || ' pp(i) := ''Empno: '' || c.empno; i := i+1; ' || ' pp(i) := ''Job: '' || c.job; i := i+1; ' || ' pp(i) := ''Mgr: '' || c.mgr; i := i+1; ' || ' pp(i) := ''Sal: '' || c.sal; i := i+1; ' || ' pp(i) := null; i := i+1; ' || ' END LOOP; ' || ' :1 := pp;' || 'END;', -1, 1, coll, errm); each := coll.FIRST; WHILE (each IS NOT NULL) LOOP dosomething(coll(each)); each := coll.NEXT(each); END LOOP; END;