CL can read a database file directly, without calling an RPG or SQL program, using two commands: DCLF to declare the file and generate a variable for every field, and RCVF to read one record at a time. This page builds a small read loop and explains the CL equivalent of checking %EOF. For the surrounding program skeleton, see CL Program Structure: PGM, DCL, and ENDPGM; for the variables DCLF creates, see CL Variables, Data Types, and CHGVAR.
Declaring the File with DCLF
DCLF FILE(library-name/file-name) RCDFMT(record-format-names) OPNID(open-id)
Verification level: IBM DOC CHECKED, against the IBM i 7.5 DCLF command reference.
| Parameter | Purpose | Default |
|---|---|---|
FILE | The database or display file to declare (required, positional 1) | None; library defaults to *LIBL |
RCDFMT | Which record formats to declare variables for | *ALL |
OPNID | Open file identifier, used to make multiple declarations of the same file unique | *NONE |
ALWNULL | Whether null field values are allowed | *NO |
ALWVARLEN | Whether variable-length fields are allowed | *NO |
For a simple read, naming just the file is enough:
PGM
DCLF FILE(MYLIB/CUSTOMER)
...
ENDPGM
Verification level: IBM DOC CHECKED.
The compiler generates one CL variable per field in the record format, named &fieldname (or &opnid_fieldname when OPNID is used, which matters once a program declares the same file twice or needs to distinguish fields from two files that happen to share names). DCLF is a declare command like DCL — it must come right after PGM, before any executable command, and a program can have at most five DCLF commands. Only physical and logical database files with a single usable record format, or display files, can be declared this way; files with multiple formats need RCDFMT to pick specific ones, up to 50 named formats or *ALL for up to 99.
A database file declared with DCLF is opened for input only, and only RCVF is valid against it — SNDF, SNDRCVF, and WAIT are display-file-only operations and are rejected for a database file.
Reading Records with RCVF
RCVF [DEV(*FILE | name)] [RCDFMT(*FILE | name)] [OPNID(*NONE | name)] [WAIT(*YES | *NO)]
Verification level: IBM DOC CHECKED, against the IBM i 7.5 RCVF command reference.
For a database file, the plain form is all that’s needed:
RCVF
The WAIT and DEV parameters apply only to display device files; the IBM i 7.5 reference states this restriction explicitly for both parameters, and specifying either against a database file is rejected. A database file is implicitly opened on the first RCVF against it and stays open for input until the program ends or the end-of-file condition described below is reached.
Each RCVF populates the field variables that DCLF declared with the next record’s values. There is no separate “read” statement — RCVF is both the open-on-first-use and the per-record read.
End of File: MONMSG CPF0864
CL has no %EOF built-in function. Instead, when RCVF runs past the last record, the file sends the program an escape message, CPF0864 (“End of file detected for file &1 in &2”), and the standard pattern is a label, a read, a MONMSG that branches out of the loop, and the record-processing logic:
PGM
DCLF FILE(MYLIB/CUSTOMER)
DCL VAR(&COUNT) TYPE(*DEC) LEN(5 0) VALUE(0)
READLOOP:
RCVF
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(DONE))
CHGVAR VAR(&COUNT) VALUE(&COUNT + 1)
/* process &CUSTNO, &CUSTNM, and other declared fields here */
GOTO CMDLBL(READLOOP)
DONE:
SNDPGMMSG MSG('Read' *CAT %CHAR(&COUNT) *CAT 'customer records.') TOPGMQ(*EXT)
ENDPGM
Verification level: IBM DOC CHECKED. This loop structure matches the pattern shown in the IBM RCVF reference’s own end-of-file example; it has not been compiled or run.
Mechanically this is CL’s version of a DOU %EOF() loop in RPGLE: the MONMSG right after RCVF is the equivalent of checking the end-of-file indicator before processing the record, except CL expresses it as a message monitor and a GOTO rather than a boolean test.
Two rules make this pattern easy to get wrong:
- If
CPF0864is not monitored, the program does not simply stop — it goes into an inquiry message wait (MSGW) once the unhandled escape message reaches the top of the call stack with no monitor, which on an interactive job means the session hangs waiting for an operator reply. See IBM i Troubleshooting Guide if a job is already stuck this way. - Once a given
RCVFagainst a file has returnedCPF0864within the current program activation, furtherRCVFcalls against that same open instance keep returningCPF0864. The file does not automatically reposition to the start. Reading the file again within the same program run typically means closing and reopening it — with theCLOSEcommand (CLOSE OPNID(opnid), or plainCLOSEfor the default open identifier), notCLOF.CLOSEis documented specifically for a database file thatRCVFimplicitly opened against aDCLFdeclaration in the same program or ILE CL procedure;CLOFis a different command for files opened withOPNDBForOPNQRYF, which is not how aDCLF/RCVFfile is opened. The nextRCVFafterCLOSEreopens the file and reads from the start. An alternative is to drive the read from a separately called program instead of closing and reopening in place.
Putting It Together
A complete small program that totals an amount field while reading a physical file:
PGM
DCLF FILE(MYLIB/ORDERS)
DCL VAR(&TOTAL) TYPE(*DEC) LEN(11 2) VALUE(0)
READLOOP:
RCVF
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(DONE))
CHGVAR VAR(&TOTAL) VALUE(&TOTAL + &ORDAMT)
GOTO CMDLBL(READLOOP)
DONE:
SNDPGMMSG MSG('Order total:' *CAT %CHAR(&TOTAL)) TOPGMQ(*EXT)
ENDPGM
Verification level: IBM DOC CHECKED. Not compiled or run; &ORDAMT is illustrative and assumes a field of that name exists in the ORDERS record format.
Compile it the same way as any other CL program, per CL Program Structure: PGM, DCL, and ENDPGM:
CRTBNDCL PGM(MYLIB/ORDTOTAL) SRCFILE(MYLIB/QCLSRC) SRCMBR(ORDTOTAL)
Common Mistakes
- Forgetting the
MONMSG CPF0864afterRCVF. The job ends up waiting in MSGW instead of exiting the loop cleanly. - Trying to
RCVFa database file withWAITorDEVset. Those parameters are display-file-only and the command is rejected. - Declaring more than five files with
DCLFin one program. The limit is five; split the work across multiple programs if more are genuinely needed. - Expecting a second pass over the file within the same program run without reopening it. Once
CPF0864has been returned for that open instance, it keeps being returned.
Summary
DCLF FILE(lib/file)declares a database file and generates one variable per field, up to five files per program.RCVFreads the next record; for database files, omitWAITandDEV, which are display-file-only.- End of file is the escape message
CPF0864, handled withMONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(label))right afterRCVF— CL’s structural equivalent of checking%EOF. - Once a file hits end of file in a program’s open instance, that instance cannot
RCVFit again without reopening.
Sources: IBM i 7.5 DCLF command, IBM i 7.5 RCVF command, and IBM i 7.5 CLOSE command. All examples are documentation-checked only; none were compiled or run.
For error handling beyond a single MONMSG, see IBM i Message Files, Exception Handling and CL. For what to do when a job is actually stuck waiting on a message, see IBM i Troubleshooting Guide.