Appendix A: Enterprise COBOL Quick Reference
This appendix is a working reference, not a tutorial. It assumes you already know COBOL and need to look something up quickly — a PIC pattern you use twice a year, the exact syntax for UNSTRING, or which compiler option controls bounds checking. Keep it bookmarked.
All examples target IBM Enterprise COBOL for z/OS (V6.x). Where GnuCOBOL diverges, the difference is noted.
The Four Divisions
IDENTIFICATION DIVISION
IDENTIFICATION DIVISION.
PROGRAM-ID. PRGNAME.
AUTHOR. Your Name.
DATE-WRITTEN. 2026-03-17.
DATE-COMPILED.
PROGRAM-ID is the only required paragraph. The name must match (or at least align with) your load module name. AUTHOR and DATE-WRITTEN are documentation only — the compiler ignores them. DATE-COMPILED is replaced by the actual compile date/time in the listing.
For nested programs or called subprograms:
PROGRAM-ID. SUBPGM IS INITIAL.
IS INITIAL resets all Working-Storage to its initial value each time the program is called. Without it, Working-Storage persists across calls — which is sometimes what you want (counters, cached data) and sometimes a source of subtle bugs.
ENVIRONMENT DIVISION
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SOURCE-COMPUTER. IBM-370.
OBJECT-COMPUTER. IBM-370.
SPECIAL-NAMES.
DECIMAL-POINT IS COMMA.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT INFILE ASSIGN TO INPUTDD
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS WS-INFILE-STATUS.
SELECT IDXFILE ASSIGN TO IDXDD
ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS IDX-PRIMARY-KEY
ALTERNATE RECORD KEY IS IDX-ALT-KEY
WITH DUPLICATES
FILE STATUS IS WS-IDXFILE-STATUS.
SELECT SORTFILE ASSIGN TO SORTWORK.
File organizations:
| Organization | Access Modes | Typical DD |
|---|---|---|
| SEQUENTIAL | SEQUENTIAL | QSAM, tape |
| INDEXED | SEQUENTIAL, RANDOM, DYNAMIC | VSAM KSDS |
| RELATIVE | SEQUENTIAL, RANDOM, DYNAMIC | VSAM RRDS |
| LINE SEQUENTIAL | SEQUENTIAL | GnuCOBOL only |
Always code FILE STATUS. Always check it. Programs that skip file status checking account for a disproportionate share of midnight production calls.
DATA DIVISION
DATA DIVISION.
FILE SECTION.
FD INFILE
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS
RECORD CONTAINS 80 CHARACTERS.
01 INFILE-RECORD PIC X(80).
WORKING-STORAGE SECTION.
01 WS-FIELDS.
05 WS-COUNTER PIC 9(07) COMP-3.
05 WS-FLAG PIC X(01).
88 WS-EOF VALUE 'Y'.
88 WS-NOT-EOF VALUE 'N'.
LOCAL-STORAGE SECTION.
01 LS-WORK-AREA PIC X(100).
LINKAGE SECTION.
01 LS-PARM-AREA.
05 LS-PARM-LENGTH PIC S9(04) COMP.
05 LS-PARM-DATA PIC X(100).
Working-Storage vs. Local-Storage: Working-Storage is allocated once and persists for the life of the run unit. Local-Storage is allocated fresh on each invocation — crucial for reentrant CICS programs and recursive calls.
BLOCK CONTAINS 0 RECORDS tells the system to use the blocksize from the DCB or data set label. Always code this rather than hard-coding a block size.
PROCEDURE DIVISION
PROCEDURE DIVISION.
PROCEDURE DIVISION USING LS-PARM-AREA.
PROCEDURE DIVISION USING LS-PARM-AREA
RETURNING WS-RESULT.
PIC Clause Patterns
Numeric
| Pattern | Meaning | Storage (Display) | Example Value |
|---|---|---|---|
PIC 9(5) |
5-digit unsigned | 5 bytes | 00123 |
PIC S9(5) |
5-digit signed | 5 bytes + sign | -00123 |
PIC S9(7)V99 |
7.2 digits signed | 10 bytes display | -0001234.56 |
PIC 9(7)V99 COMP-3 |
7.2 packed | 5 bytes | 1234567.89 |
PIC S9(8) COMP |
Binary fullword | 4 bytes | -12345678 |
PIC S9(4) COMP |
Binary halfword | 2 bytes | -1234 |
PIC S9(18) COMP |
Binary doubleword | 8 bytes | large integer |
Alphanumeric
| Pattern | Meaning | Storage |
|---|---|---|
PIC X(10) |
10-char alphanumeric | 10 bytes |
PIC A(10) |
10-char alphabetic | 10 bytes |
PIC X(1) |
Single character | 1 byte |
Edited (for reports)
| Pattern | Example Input | Example Output |
|---|---|---|
PIC Z(5)9 |
000123 | 123 |
PIC ZZ,ZZ9 |
01234 | 1,234 |
PIC $ZZ,ZZ9.99` | 0012345.67 | ` $12,345.67 |
||
PIC -(5)9.99 |
-001234.56 | -1234.56 |
PIC 99/99/9999 |
03172026 | 03/17/2026 |
PIC X(5)BX(5) |
HELLOWORLD | HELLO WORLD |
COMP Types Summary
| Type | Also Called | Storage | Use Case |
|---|---|---|---|
| COMP (COMP-4) | BINARY | 2/4/8 bytes | Subscripts, counters, binary interfaces |
| COMP-1 | — | 4 bytes | Single-precision float (rare in business) |
| COMP-2 | — | 8 bytes | Double-precision float (rare in business) |
| COMP-3 | PACKED-DECIMAL | (n+1)/2 bytes | Money, business arithmetic — the default choice |
| COMP-5 | NATIVE BINARY | 2/4/8 bytes | Full binary range, C/Java interop |
The rule of thumb: Use COMP-3 for business data, COMP/COMP-4 for subscripts and counters, COMP-5 for calling non-COBOL APIs. Avoid COMP-1 and COMP-2 unless interfacing with scientific code.
Key Statements
PERFORM
* Inline PERFORM
PERFORM VARYING WS-IDX FROM 1 BY 1
UNTIL WS-IDX > WS-MAX
MOVE SPACES TO WS-LINE(WS-IDX)
END-PERFORM
* Out-of-line PERFORM
PERFORM 1000-PROCESS-RECORD
THRU 1000-EXIT
* PERFORM TIMES
PERFORM 2000-RETRY 3 TIMES
* PERFORM UNTIL
PERFORM 3000-READ-NEXT
UNTIL WS-EOF
THRU (or THROUGH) is a shop-standards issue. Some shops mandate it for every paragraph; others ban it. When using THRU, ensure the exit paragraph exists and contains only EXIT or CONTINUE.
EVALUATE (Structured CASE)
EVALUATE TRUE
WHEN WS-TRANS-TYPE = 'A'
PERFORM 2100-ADD-RECORD
WHEN WS-TRANS-TYPE = 'C'
PERFORM 2200-CHANGE-RECORD
WHEN WS-TRANS-TYPE = 'D'
PERFORM 2300-DELETE-RECORD
WHEN OTHER
PERFORM 2900-INVALID-TRANS
END-EVALUATE
* Multi-subject EVALUATE
EVALUATE WS-REGION ALSO WS-PRODUCT
WHEN 'EAST' ALSO 'WIDGET'
MOVE 0.10 TO WS-DISCOUNT
WHEN 'EAST' ALSO ANY
MOVE 0.05 TO WS-DISCOUNT
WHEN ANY ALSO 'WIDGET'
MOVE 0.07 TO WS-DISCOUNT
WHEN OTHER
MOVE 0.00 TO WS-DISCOUNT
END-EVALUATE
STRING
STRING WS-LAST-NAME DELIMITED BY SPACES
', ' DELIMITED BY SIZE
WS-FIRST-NAME DELIMITED BY SPACES
INTO WS-FULL-NAME
WITH POINTER WS-PTR
ON OVERFLOW
MOVE 'Y' TO WS-OVERFLOW-FLAG
END-STRING
Initialize WS-PTR to 1 before the first STRING. If building a string in multiple STRING statements, do not reset the pointer between them — that is the whole point of the POINTER phrase.
UNSTRING
UNSTRING WS-CSV-RECORD
DELIMITED BY ',' OR ALL SPACES
INTO WS-FIELD-1
WS-FIELD-2
WS-FIELD-3
WITH POINTER WS-PTR
TALLYING IN WS-FIELD-COUNT
ON OVERFLOW
PERFORM 9100-PARSE-ERROR
END-UNSTRING
TALLYING gives you the number of receiving fields that were populated. ON OVERFLOW fires when there are more delimited fields than receiving fields.
INSPECT
* Count occurrences
INSPECT WS-INPUT-STRING
TALLYING WS-COMMA-COUNT
FOR ALL ','
* Replace characters
INSPECT WS-INPUT-STRING
REPLACING ALL LOW-VALUES BY SPACES
* Convert (translate)
INSPECT WS-INPUT-STRING
CONVERTING 'abcdefghijklmnopqrstuvwxyz'
TO 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
COMPUTE
COMPUTE WS-RESULT ROUNDED
= (WS-PRINCIPAL * WS-RATE ** WS-YEARS)
ON SIZE ERROR
PERFORM 9200-OVERFLOW-ERROR
END-COMPUTE
COMPUTE is the only statement that supports exponentiation (**), parenthetical grouping, and mixed arithmetic in a single expression. For anything beyond simple ADD/SUBTRACT/MULTIPLY/DIVIDE, prefer COMPUTE.
ROUNDED rounds the final result. Without it, truncation occurs. For financial calculations, always code ROUNDED.
ON SIZE ERROR fires on overflow or division by zero. Always code it for production arithmetic.
CALL
* Static call
CALL 'SUBPGM01' USING WS-REQUEST-AREA
WS-RESPONSE-AREA
* Dynamic call
MOVE 'SUBPGM01' TO WS-PGM-NAME
CALL WS-PGM-NAME USING WS-REQUEST-AREA
WS-RESPONSE-AREA
ON EXCEPTION
PERFORM 9300-PGM-NOT-FOUND
END-CALL
* CALL with BY REFERENCE / BY CONTENT / BY VALUE
CALL 'SUBPGM02' USING BY REFERENCE WS-AREA-1
BY CONTENT WS-AREA-2
BY VALUE WS-LENGTH
BY REFERENCE (default): callee sees and can modify the caller's storage. BY CONTENT: callee gets a copy; changes do not affect the caller. BY VALUE: passes the actual value (not a pointer); required for calling C functions.
Static calls are resolved at link-edit — the subprogram is bound into the load module. Dynamic calls are resolved at runtime via the CALL literal or identifier — the subprogram is a separate load module. Dynamic calls cost more at first invocation (fetch from STEPLIB) but allow individual subprogram replacement without relinking.
EXEC SQL (Embedded DB2)
EXEC SQL
SELECT FIRST_NAME, LAST_NAME, SALARY
INTO :WS-FIRST-NAME,
:WS-LAST-NAME,
:WS-SALARY :WS-SALARY-NULL
FROM EMPLOYEE
WHERE EMPLOYEE_ID = :WS-EMP-ID
END-EXEC
EVALUATE SQLCODE
WHEN 0
CONTINUE
WHEN +100
MOVE 'Y' TO WS-NOT-FOUND
WHEN OTHER
PERFORM 9500-DB2-ERROR
END-EVALUATE
Every EXEC SQL must be followed by an SQLCODE check. No exceptions. Not even for COMMIT.
EXEC CICS
EXEC CICS READ
FILE('CUSTMAST')
INTO(WS-CUST-RECORD)
LENGTH(WS-CUST-LENGTH)
RIDFLD(WS-CUST-KEY)
RESP(WS-CICS-RESP)
RESP2(WS-CICS-RESP2)
END-EXEC
EVALUATE WS-CICS-RESP
WHEN DFHRESP(NORMAL)
CONTINUE
WHEN DFHRESP(NOTFND)
PERFORM 8100-CUSTOMER-NOT-FOUND
WHEN OTHER
PERFORM 9600-CICS-ERROR
END-EVALUATE
Always use RESP/RESP2 instead of HANDLE CONDITION. HANDLE CONDITION is a GOTO in disguise and makes programs nearly impossible to debug.
COPY and REPLACE
* Basic COPY
COPY CUSTCOPY.
* COPY with REPLACING
COPY CUSTCOPY REPLACING ==:PREFIX:== BY ==WS-CUST==.
* REPLACE (independent of COPY)
REPLACE ==:TAG:== BY ==PROD==.
01 :TAG:-RECORD.
05 :TAG:-ID PIC X(10).
REPLACE OFF.
COPY pulls in a copybook from the SYSLIB concatenation. REPLACING modifies text during the copy. REPLACE is a standalone directive that modifies source text — useful for generating multiple similar structures from a single template.
The == pseudo-text delimiters are required. The replacement is purely textual — the compiler does a literal string substitution before parsing.
Common Copybook Conventions
| Copybook | Contents |
|---|---|
SQLCA |
DB2 SQL Communication Area (COPY SQLCA) |
DFHAID |
CICS attention identifier definitions |
DFHBMSCA |
CICS BMS attribute characters |
DFHEIBLK |
CICS EIB (Execute Interface Block) |
Compiler Options That Matter
These are the options you will actually adjust in production. The full list runs to hundreds; these are the ones that affect your daily work.
Optimization and Performance
| Option | Default | Recommendation | Effect |
|---|---|---|---|
OPT(0) |
OPT(0) | OPT(2) for production |
Optimization level. OPT(2) yields 10-30% throughput improvement. |
FASTSRT |
NOFASTSRT | FASTSRT always |
Lets DFSORT handle SORT/MERGE I/O directly, bypassing COBOL file handling. Major performance gain. |
NUMPROC(PFD) |
NUMPROC(NOPFD) | NUMPROC(PFD) if data is clean |
Assumes valid packed decimal signs. Faster, but S0C7 on bad data. |
TRUNC(OPT) |
TRUNC(STD) | TRUNC(OPT) for new code |
Lets compiler choose optimal truncation. TRUNC(BIN) for C interop. |
HGPR(PRESERVE) |
HGPR(PRESERVE) | Default is fine | Controls use of high halves of 64-bit GPRs. |
AFP(VOLATILE) |
AFP(VOLATILE) | Default is fine | Controls additional floating-point registers. |
Debugging and Safety
| Option | Default | Recommendation | Effect |
|---|---|---|---|
TEST |
NOTEST | TEST(NOEJPD,SOURCE) in dev |
Enables Debug Tool. Remove for production (except TEST(NOEJPD,NOSOURCE) for post-mortem). |
SSRANGE |
NOSSRANGE | SSRANGE in dev |
Bounds-checks subscripts and reference modifications. Catches S0C4 causes before they happen. 5-15% runtime cost. |
CHECK(ON) |
CHECK(OFF) | CHECK(ON) in dev |
Numeric validation on MOVE. Catches S0C7 sources. |
LIST |
NOLIST | LIST for tuning |
Generates assembler listing. Essential for performance tuning. |
OFFSET |
NOOFFSET | OFFSET for production |
Generates condensed offset listing. Needed to map abend offsets to COBOL statements. |
Arithmetic and Data
| Option | Default | Recommendation | Effect |
|---|---|---|---|
ARITH(COMPAT) |
ARITH(COMPAT) | ARITH(EXTEND) for new code |
COMPAT: max 18 digits. EXTEND: max 31 digits. EXTEND required for large financial calculations. |
INTDATE(ANSI) |
INTDATE(ANSI) | Check your installation | Affects date intrinsic functions. ANSI: day 1 = Jan 1, 1601. LILIAN: day 1 = Oct 15, 1582. |
NSYMBOL(NATIONAL) |
NSYMBOL(DBCS) | NSYMBOL(NATIONAL) for Unicode |
Controls interpretation of N literals. |
CODEPAGE(1140) |
Installation default | Match your data | EBCDIC code page. 1140 = US English with Euro sign. |
Compilation Control
| Option | Default | Recommendation | Effect |
|---|---|---|---|
RENT |
RENT | RENT always for CICS |
Generates reentrant code. Required for CICS, recommended everywhere. |
DYNAM |
NODYNAM | Depends on design | Dynamic call resolution. NODYNAM for static calls, DYNAM for dynamic. |
LIB |
LIB | LIB always |
Enables COPY/REPLACE processing. |
SQL |
NOSQL | SQL when using DB2 |
Enables DB2 coprocessor. |
CICS |
NOCICS | CICS when using CICS |
Enables CICS coprocessor. |
THREAD |
NOTHREAD | THREAD for DB2 stored procs |
Enables thread-safe code. |
Recommended Dev vs. Prod Profiles
Development:
OPT(0),SSRANGE,TEST(NOEJPD,SOURCE),CHECK(ON),LIST,OFFSET,
FASTSRT,RENT,LIB,ARITH(EXTEND),NUMPROC(NOPFD)
Production:
OPT(2),NOSSRANGE,NOTEST,NOCHECK,NOLIST,OFFSET,
FASTSRT,RENT,LIB,ARITH(EXTEND),NUMPROC(PFD),TRUNC(OPT)
Common Abbreviations and Acronyms
| Abbreviation | Meaning |
|---|---|
| BMS | Basic Mapping Support (CICS screen maps) |
| CICS | Customer Information Control System |
| COMP | Computational (binary) |
| COMP-3 | Packed decimal |
| COPY | Source library inclusion |
| CSECT | Control Section |
| DB2 | Database 2 (IBM relational DBMS) |
| DCB | Data Control Block |
| DISP | Disposition (JCL) |
| DFSORT | Data Facility Sort |
| DSN | Data Set Name |
| DSORG | Data Set Organization |
| EIB | Execute Interface Block (CICS) |
| FD | File Description |
| GDG | Generation Data Group |
| IEBGENER | Utility: copy sequential data sets |
| IDCAMS | Utility: VSAM catalog services |
| ISPF | Interactive System Productivity Facility |
| JCL | Job Control Language |
| JES | Job Entry Subsystem |
| KSDS | Key-Sequenced Data Set (VSAM) |
| LRECL | Logical Record Length |
| MRO | Multi-Region Operation (CICS) |
| MVS | Multiple Virtual Storage |
| PDS | Partitioned Data Set |
| PDSE | Partitioned Data Set Extended |
| QSAM | Queued Sequential Access Method |
| RECFM | Record Format |
| SD | Sort-file Description |
| SQLCA | SQL Communication Area |
| SYSOUT | System output (JES spool) |
| TSO | Time Sharing Option |
| VSAM | Virtual Storage Access Method |
| WLM | Workload Manager |
| WTO | Write To Operator |
| z/OS | IBM's flagship mainframe operating system |
Intrinsic Functions Quick List
Numeric
| Function | Example | Result |
|---|---|---|
FUNCTION LENGTH(x) |
FUNCTION LENGTH(WS-NAME) |
Length in bytes |
FUNCTION MAX(a b c) |
FUNCTION MAX(10 20 5) |
20 |
FUNCTION MIN(a b c) |
FUNCTION MIN(10 20 5) |
5 |
FUNCTION MOD(a b) |
FUNCTION MOD(17 5) |
2 |
FUNCTION INTEGER-PART(x) |
FUNCTION INTEGER-PART(3.7) |
3 |
FUNCTION NUMVAL(x) |
FUNCTION NUMVAL(' 123.45') |
123.45 |
FUNCTION NUMVAL-C(x) |
FUNCTION NUMVAL-C('$1,234.56') |
1234.56 |
FUNCTION ORD(x) |
FUNCTION ORD('A') |
194 (EBCDIC) |
String
| Function | Example | Result |
|---|---|---|
FUNCTION UPPER-CASE(x) |
FUNCTION UPPER-CASE('hello') |
'HELLO' |
FUNCTION LOWER-CASE(x) |
FUNCTION LOWER-CASE('HELLO') |
'hello' |
FUNCTION REVERSE(x) |
FUNCTION REVERSE('ABC') |
'CBA' |
FUNCTION TRIM(x) |
FUNCTION TRIM(WS-NAME) |
Leading/trailing spaces removed |
FUNCTION TRIM(x LEADING) |
FUNCTION TRIM(WS-NAME LEADING) |
Leading spaces removed |
Date/Time
| Function | Example | Notes |
|---|---|---|
FUNCTION CURRENT-DATE |
21-byte alphanumeric | YYYYMMDDHHMMSShhZ+HHMM |
FUNCTION INTEGER-OF-DATE(d) |
FUNCTION INTEGER-OF-DATE(20260317) |
Integer date |
FUNCTION DATE-OF-INTEGER(n) |
FUNCTION DATE-OF-INTEGER(155457) |
YYYYMMDD |
FUNCTION WHEN-COMPILED |
21-byte alphanumeric | Compile date/time |
Date arithmetic example:
COMPUTE WS-DAYS-BETWEEN =
FUNCTION INTEGER-OF-DATE(WS-END-DATE) -
FUNCTION INTEGER-OF-DATE(WS-START-DATE)
Reference Modification
* identifier(start:length)
MOVE WS-FULL-NAME(1:10) TO WS-SHORT-NAME
MOVE WS-RECORD(WS-OFFSET:WS-LEN) TO WS-FIELD
Start position is 1-based. If length is omitted, it extends to the end of the field. With SSRANGE active, out-of-bounds references generate a runtime error instead of silently corrupting memory.
Condition Names (88-levels)
01 WS-STATUS PIC X(02).
88 WS-ACTIVE VALUE 'AC'.
88 WS-INACTIVE VALUE 'IN'.
88 WS-SUSPENDED VALUE 'SU'.
88 WS-VALID-STATUS VALUE 'AC' 'IN' 'SU'.
Use SET WS-ACTIVE TO TRUE to assign the value 'AC' to WS-STATUS. This is cleaner than MOVE 'AC' TO WS-STATUS and self-documenting.
88-levels with multiple values are ideal for validation:
IF NOT WS-VALID-STATUS
PERFORM 9100-INVALID-STATUS
END-IF
File Status Codes
| Code | Meaning |
|---|---|
| 00 | Successful |
| 02 | Successful, duplicate key (VSAM alternate index) |
| 04 | Record length mismatch (not serious) |
| 10 | End of file (AT END) |
| 22 | Duplicate key on WRITE (VSAM KSDS) |
| 23 | Record not found (VSAM RANDOM READ) |
| 30 | Permanent I/O error |
| 34 | Out of space on WRITE |
| 35 | File not found (OPEN) |
| 37 | File attribute conflict (OPEN) |
| 39 | File attribute mismatch |
| 41 | File already open |
| 42 | File already closed |
| 46 | Sequential read without position |
| 47 | File not open for READ |
| 48 | File not open for WRITE |
| 49 | File not open for REWRITE/DELETE |
| 92 | Logic error |
| 93 | Resource not available |
| 95 | Incomplete/wrong length record |
| 96 | No DD statement found |
SORT and MERGE
SORT SORT-FILE
ON ASCENDING KEY SORT-CUST-ID
ON DESCENDING KEY SORT-AMOUNT
INPUT PROCEDURE IS 4000-SELECT-RECORDS
OUTPUT PROCEDURE IS 5000-PROCESS-SORTED
* Simple SORT with USING/GIVING
SORT SORT-FILE
ON ASCENDING KEY SORT-KEY
USING INPUT-FILE
GIVING OUTPUT-FILE
With FASTSRT, USING/GIVING bypasses COBOL I/O entirely — DFSORT reads and writes the files directly. This is significantly faster but means COBOL OPEN/CLOSE/READ/WRITE processing does not apply to those files.
Scope Terminators
Always use explicit scope terminators. Every shop's code review should enforce this.
| Statement | Terminator |
|---|---|
| IF | END-IF |
| EVALUATE | END-EVALUATE |
| PERFORM | END-PERFORM |
| READ | END-READ |
| WRITE | END-WRITE |
| REWRITE | END-REWRITE |
| DELETE | END-DELETE |
| START | END-START |
| STRING | END-STRING |
| UNSTRING | END-UNSTRING |
| COMPUTE | END-COMPUTE |
| ADD | END-ADD |
| SUBTRACT | END-SUBTRACT |
| MULTIPLY | END-MULTIPLY |
| DIVIDE | END-DIVIDE |
| CALL | END-CALL |
| SEARCH | END-SEARCH |
| EXEC SQL | END-EXEC |
| EXEC CICS | END-EXEC |
Table Handling
01 WS-STATE-TABLE.
05 WS-STATE-ENTRY OCCURS 50 TIMES
INDEXED BY WS-STATE-IDX.
10 WS-STATE-CODE PIC X(02).
10 WS-STATE-NAME PIC X(20).
10 WS-TAX-RATE PIC V9(04) COMP-3.
* SEARCH (serial)
SET WS-STATE-IDX TO 1
SEARCH WS-STATE-ENTRY
AT END
PERFORM 9100-STATE-NOT-FOUND
WHEN WS-STATE-CODE(WS-STATE-IDX) =
WS-INPUT-STATE
MOVE WS-TAX-RATE(WS-STATE-IDX)
TO WS-OUTPUT-RATE
END-SEARCH
* SEARCH ALL (binary — table must be sorted)
01 WS-STATE-TABLE-SORTED.
05 WS-STATE-ENTRY OCCURS 50 TIMES
ASCENDING KEY IS WS-STATE-CODE
INDEXED BY WS-STATE-IDX.
10 WS-STATE-CODE PIC X(02).
10 WS-STATE-NAME PIC X(20).
10 WS-TAX-RATE PIC V9(04) COMP-3.
SEARCH ALL WS-STATE-ENTRY
AT END
PERFORM 9100-STATE-NOT-FOUND
WHEN WS-STATE-CODE(WS-STATE-IDX) =
WS-INPUT-STATE
MOVE WS-TAX-RATE(WS-STATE-IDX)
TO WS-OUTPUT-RATE
END-SEARCH
SEARCH ALL requires the table to be defined with ASCENDING KEY (or DESCENDING KEY) and the table data must actually be in that order. The compiler generates a binary search — O(log n) vs. O(n) for serial SEARCH.
Variable-Length Records and OCCURS DEPENDING ON
FD VARFILE
RECORDING MODE IS V
RECORD IS VARYING IN SIZE
FROM 50 TO 500 CHARACTERS
DEPENDING ON WS-RECORD-LENGTH.
01 WS-VAR-TABLE.
05 WS-NUM-ENTRIES PIC S9(04) COMP.
05 WS-TABLE-ENTRY OCCURS 1 TO 100 TIMES
DEPENDING ON WS-NUM-ENTRIES.
10 WS-ENTRY-DATA PIC X(20).
Set WS-NUM-ENTRIES before any reference to the table. The compiler uses it to calculate the actual length of WS-VAR-TABLE. Getting this wrong causes S0C4 or data corruption.
This reference is deliberately terse. For full syntax diagrams and edge-case behavior, consult the Enterprise COBOL for z/OS Language Reference (SC27-1408) — the definitive authority. For compiler option details, see the Programming Guide (SC27-1412). Both are available on the IBM Documentation website at no cost.