Programming on IBM i: sources, ILE, RPG and SQL Chapter 7 of 9

When it breaks: errors and debugging

Reviewed on Verified on IBM i 7.5

Log in to save

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.

Sources

Back to the guide index

← Back to blog

Comments

No comments yet. Be the first to comment!

You need an account to comment. Log in · Sign up