MODULE 10 · BATCH REPORTS · 1/7

Anatomy of a batch report

12 min10 XPQuiz

Long before dashboards, the output of a batch job was paper: a stack of green-bar listings on someone's desk in the morning. Most of those reports are now PDFs or files that land in a document system, but the programs that make them are the same, and changing a report is one of the most common tickets a junior COBOL developer gets.

The parts of a report

BRANCH DEPOSIT LIST       PAGE  1      <- page heading (title, page no.)
ACCOUNT NAME              AMOUNT       <- column headings
100200  JANE DOE        1,250.50       <- detail lines, one per record
300100  GRACE HOPPER       75.00-
  TOTAL DEPOSITS        1,175.50       <- total line(s)
  • Page heading: report title, run date, page number. Repeated on every page.
  • Column headings: aligned over the columns below them.
  • Detail lines: one per input record (or per group, in a summary report).
  • Control totals: subtotals when a group ends (a control break) and grand totals at the end.

Each kind of line is a WORKING-STORAGE group. FILLER items with VALUE hold spacing and literal text; named fields, often edited pictures, receive the data. The column positions are simply the sum of the PIC sizes before them:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. RPTDEMO.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 HDG-1.
          05 FILLER       PIC X(20) VALUE "BRANCH DEPOSIT LIST".
          05 FILLER       PIC X(6)  VALUE SPACES.
          05 FILLER       PIC X(5)  VALUE "PAGE ".
          05 H1-PAGE      PIC Z9.
       01 HDG-2.
          05 FILLER       PIC X(8)  VALUE "ACCOUNT".
          05 FILLER       PIC X(14) VALUE "NAME".
          05 FILLER       PIC X(10) VALUE "    AMOUNT".
       01 DETAIL-LINE.
          05 DL-ACCT      PIC X(6).
          05 FILLER       PIC X(2)  VALUE SPACES.
          05 DL-NAME      PIC X(12).
          05 FILLER       PIC X(2)  VALUE SPACES.
          05 DL-AMOUNT    PIC ZZZ,ZZ9.99-.
       01 TOTAL-LINE.
          05 FILLER       PIC X(22) VALUE "  TOTAL DEPOSITS".
          05 TL-AMOUNT    PIC ZZZ,ZZ9.99-.
       01 WS-TOTAL        PIC S9(6)V99 VALUE 0.
       PROCEDURE DIVISION.
           MOVE 1 TO H1-PAGE
           DISPLAY HDG-1
           DISPLAY HDG-2
           MOVE "100200" TO DL-ACCT
           MOVE "JANE DOE" TO DL-NAME
           MOVE 1250.5 TO DL-AMOUNT
           ADD 1250.5 TO WS-TOTAL
           DISPLAY DETAIL-LINE
           MOVE "300100" TO DL-ACCT
           MOVE "GRACE HOPPER" TO DL-NAME
           MOVE -75 TO DL-AMOUNT
           ADD -75 TO WS-TOTAL
           DISPLAY DETAIL-LINE
           MOVE WS-TOTAL TO TL-AMOUNT
           DISPLAY TOTAL-LINE
           STOP RUN.

Output:

BRANCH DEPOSIT LIST       PAGE  1
ACCOUNT NAME              AMOUNT
100200  JANE DOE        1,250.50
300100  GRACE HOPPER       75.00-
  TOTAL DEPOSITS        1,175.50

To put a line in a report file instead of on SYSOUT, write it: WRITE RPT-LINE FROM DETAIL-LINE, where RPT-LINE is the FD record.

Printers, ASA and this course

On z/OS a print dataset is usually RECFM=FBA, LRECL=133: byte 1 is an ASA carriage-control character (1 new page, blank single space, 0 double space) and the next 132 bytes are the line. You don't set that byte yourself; you write

           WRITE RPT-LINE FROM HDG-1 AFTER ADVANCING PAGE
           WRITE RPT-LINE FROM DETAIL-LINE AFTER ADVANCING 1 LINE

and the compiler fills it in. In this course, reports are plain text datasets so they can be compared line by line: use a plain WRITE for every line (one record = one line), write a line of spaces where you want a blank line, and mark new pages with the page heading itself.

Report Writer

COBOL also has a declarative Report Writer (RD entries, TYPE IS PAGE HEADING, CONTROL FOOTING, GENERATE). It works, but most shops never adopted it, so the reports you'll maintain are built procedurally, exactly as in this module.

On the job

Before changing a report, get a copy of the current output and the spec, then count columns. The classic bug is a print line that grew by one byte: every field to the right shifts, and a downstream program that reads the report by position (yes, they exist) breaks.

Check your understanding

1. Why are print lines usually built as WORKING-STORAGE groups full of FILLER?
2. On z/OS, what does a 1 in the ASA carriage-control byte of a print record mean?
3. Where does a control-break total get printed?
4. Which statement about COBOL's REPORT WRITER is accurate?