A program that does not work leaves traces in several places: the job log, the call stack, the debugger, the dump. This chapter takes them one at a time.
Reading the error
When an RPG program fails, the job log contains two separate things, and you need both.
The message. RNQ are exceptions that stop and wait for an answer, RNX those that end
the program. MCH are machine-level errors: index out of range, a numeric field holding
something that is not numeric.
The call stack. It gives the program, the procedure and the statement number. It is the information that leads straight to the spot, and it is ignored nearly every time.
DSPJOBLOG JOB(123456/JSMITH/CLOSE)
On a job still active, the stack is seen with WRKJOB, option 11.
Tip
compiling with OPTION(*SRCSTMT) makes the number in the message the source
line number, not an internal number to convert back. Worth putting on
everything you compile.
Errors handled by the program
A program can notice an error itself instead of dying. Two ways.
MONITOR, the modern form, covering a block:
monitor;
chain (number) orders;
if not %found(orders);
// record absent: an expected case
endif;
on-error;
// any error inside the block
status = 'Error reading orders';
endmon;
*PSSR, the program's error subroutine, catching whatever was not handled elsewhere
and acting as the last net before the end.
Warning
a *PSSR that merely does return turns a failure into silence. The program
ends, the job appears to have finished normally, and the data was not written. It is how
closes that "went fine" and left the file half done come about. Whatever the *PSSR does,
it must leave a trace: a message on a queue, a line in a log file, a return code the
caller checks.
The debugger
The ILE debugger works on source, provided the program was compiled with the necessary information:
CRTBNDRPG PGM(PRODLIB/INVOICES) DBGVIEW(*SOURCE)
*SOURCE shows the original source, *LIST the listing after copy members and SQL
precompilation have been expanded, which is what you need when the problem is inside a
/COPY or inside an EXEC SQL.
STRDBG PGM(PRODLIB/INVOICES) UPDPROD(*YES)
Then you set a breakpoint (F6 on the line), run the program, and stop there: F10 steps, F12 resumes, F11 shows the value of the variable under the cursor.
Warning
UPDPROD(*YES) is what lets you work against production files, and it should
be typed deliberately. In debug the statements really run: if the program writes, the
record is written. Testing against a test library, with OVRDBF pointing at test data, is
the difference between a debugging session and an incident.
The job that is not yours
The problem is in a batch job, and the debugger has to be attached from outside.
STRSRVJOB JOB(123456/JSMITH/CLOSE)
STRDBG PGM(PRODLIB/CLOSE) UPDPROD(*YES)
From then on the debug commands apply to that job: set the breakpoints, release the job, and
stop at the right place inside the real processing. You finish with ENDDBG and
ENDSRVJOB.
Tip
the procedure IBM describes for a batch job: submit it with
SBMJOB ... HOLD(*YES), read its qualified name with WRKSBMJOB or WRKJOBQ, attach with
STRSRVJOB, run STRDBG naming every program to follow (no other debug commands can be
entered while the job waits in the queue), and then release it. For a scheduled job that
fails only at night: hold the schedule entry and submit the same command this way.
The dump
When the problem will not reproduce, the snapshot remains:
dump(a);
The DUMP operation writes the module's fields, files, indicators, data structures,
arrays and tables to spooled file QPPGMDMP. With (A) it always does; without it, not if
the program has DEBUG(*NO). Two limits from IBM's page: with DBGVIEW(*NONE) it shows only
the status data structure, the file information data structures and the *IN indicators,
and with OPTIMIZE(*FULL) the values may not be the real ones.
The three things that settle most cases
Look at the first error, not the last. In a long job log the final messages describe a program already in trouble. The message that explains is the first serious one.
Check that the object matches the source. Before reading the code line by line,
DSPOBJD ... DETAIL(*SERVICE) says when the object was compiled and from which source (chapter "Where the code lives").
Look at the environment before the program. The job's library list, active overrides, activation group, ASP group. A correct program in a wrong environment behaves like a wrong program.
Comments
No comments yet. Be the first to comment!
You need an account to comment. Log in · Sign up