MODULE 8 · SEQUENTIAL FILES · 5/8

Fixed-length records

15 min30 XPExercise

So far every dataset has been LINE SEQUENTIAL: a text file with a line break after each record. That is convenient on a PC, but it is not how z/OS stores data. A mainframe sequential dataset is a string of fixed-length records with nothing between them. No line breaks, no delimiters: record 2 starts at byte 81 of an 80-byte-record dataset simply because record 1 is 80 bytes long.

RECFM and LRECL

Every z/OS dataset carries its format in the catalog:

  • RECFM=FB: fixed-length records, grouped into blocks. (VB means variable-length records, each with a small length prefix.)
  • LRECL=80: the logical record length, in bytes.
  • BLKSIZE: how many bytes are read from disk at once. The system picks a good value if you let it.

When a program opens the dataset, z/OS checks the program's record description against the catalog. If the FD says 100 bytes and the dataset has LRECL=80, the OPEN fails with file status 39.

In COBOL

Use plain ORGANIZATION IS SEQUENTIAL (it is also the default), and say how long the records are:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. FIXDEMO.
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT CODE-FILE ASSIGN TO CODES
               ORGANIZATION IS SEQUENTIAL
               FILE STATUS IS WS-STATUS.
       DATA DIVISION.
       FILE SECTION.
       FD  CODE-FILE
           RECORD CONTAINS 10 CHARACTERS.
       01  CODE-REC.
           05  CODE-KEY       PIC X(3).
           05  CODE-TEXT      PIC X(7).
       WORKING-STORAGE SECTION.
       01  WS-STATUS          PIC XX.
       PROCEDURE DIVISION.
           OPEN INPUT CODE-FILE
           READ CODE-FILE
           PERFORM UNTIL WS-STATUS NOT = "00"
               DISPLAY "[" CODE-KEY "] [" CODE-TEXT "]"
               READ CODE-FILE
           END-PERFORM
           DISPLAY "STATUS " WS-STATUS
           CLOSE CODE-FILE
           STOP RUN.

The dataset CUR.CODES is 30 bytes on one line, with no line breaks:

EUREURO   GBPPOUND  USDDOLLAR 

Output:

[EUR] [EURO   ]
[GBP] [POUND  ]
[USD] [DOLLAR ]
STATUS 10

RECORD CONTAINS 10 CHARACTERS documents the length and lets the compiler check it against the 01 level. On the mainframe you will also often see BLOCK CONTAINS 0 RECORDS, which means "use the block size from the dataset", and RECORDING MODE IS F.

When the layout is wrong

With no delimiters, the only thing that marks where a record starts is arithmetic. If the program's layout is one byte out, every record after the first drifts. The same program reading a dataset whose records are really 9 bytes long prints:

[EUR] [EURO  G]
[BPP] [OUND US]
[DDO] [LLAR US]
STATUS 10

No error, just garbage. z/OS catches the simple case with status 39 at OPEN, but not a copybook that has the right total length and the wrong fields inside. That is why the record layout (usually a shared copybook) is treated as a contract between every program that touches the file.

Numbers in fixed-length records

Fixed-length records often hold numbers that are not readable text at all: COMP-3 packed decimal and COMP binary fields, which you will meet later. In this lesson all fields are DISPLAY digits, so you can still read the data with your eyes.

On the job

Most test data problems on the mainframe come down to record layout: a file built with an old copybook, a dataset transferred from a PC with line breaks added, a field that grew by two bytes. When a program produces nonsense from a file, compare the LRECL and the copybook before anything else.

Your task

The policy system has sent a mainframe extract of insurance policies: fixed-length 40-byte records with no line breaks. Turn it into a readable report file.

Input, DD name POLICIES, ORGANIZATION IS SEQUENTIAL, RECORD CONTAINS 40 CHARACTERS:

Field Picture Positions
POL-NO X(8) 1–8
POL-HOLDER X(20) 9–28
POL-TYPE X (A auto, H home, L life) 29
POL-PREMIUM 9(5)V99 30–36
FILLER X(4) 37–40

Output, DD name POLRPT, line sequential, one line per policy (declared in the starter as RPT-REC): policy number, holder, type name (AUTO, HOME, LIFE, or ???? for any other code) and premium (Z(4)9.99), separated by single spaces:

P0000001 GRACE HOPPER         AUTO  1234.50

Then display the control totals:

POLICIES: 004
PREMIUMS:    5084.25

Check the file status after opening the input: if it is not 00, display POLICIES OPEN FAILED: and the status, and stop with return code 12.

fixed format
Run your program to see its output here. The first visible test's input and datasets are used.
Submit to grade your program against every test.