Data Division and Level Numbers

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This page is written against ISO/IEC 1989:2023 (edition 3, January 2023; a 4th edition is upcoming), GnuCOBOL 3.2 and IBM Enterprise COBOL for z/OS 6.5, checked on 2026-10-20. Every program below was compiled with cobc -x -Wall (GnuCOBOL 3.2.0) and run. The ones presented as working compiled without warnings (also under -std=ibm), and the deliberately wrong ones show the real diagnostics. They use the Circulation library scenario of this section (copybooks BOOKREC and MEMBREC, file BOOKMAST). z/OS-only statements are labelled as not run here.

The data division is where every item a program touches is declared: its name, its position in a record hierarchy, its size and its format. COBOL has no local variables declared next to the code that uses them. Everything lives in one declarative block, and the level numbers are what give that block its structure. This page covers sections, level numbers, group and elementary items, qualification and the three storage clauses GLOBAL, EXTERNAL and BASED. What goes after the level number is covered elsewhere: The PICTURE Clause, USAGE and Numeric Representation, VALUE, INITIALIZE and Condition Names and REDEFINES, RENAMES and TYPEDEF. The overall program skeleton is on Program Structure and Divisions.

Sections of the data division

The data division is optional and is made of sections that must appear in this order. Each section can be omitted when a program has nothing to put in it.

Section What it describes Lifetime of the storage

FILE SECTION

The record areas of the files named in FD (file description) and SD (sort description) entries. A record area is the buffer the runtime reads into and writes from. See File Concepts, SELECT and FD.

Allocated for the run unit; its contents are meaningful only while the file is open and after a successful read or before a write

WORKING-STORAGE SECTION

The program’s own variables, constants and tables

Allocated when the program is first called and kept until the run unit ends, so values survive between calls. The initial contents come from VALUE clauses, set once (and again on CANCEL or for an INITIAL program)

LOCAL-STORAGE SECTION

Variables that must be fresh on every call, which is also what makes a program able to call itself recursively

Allocated and reinitialised from VALUE clauses each time the program is called, and released when it returns

LINKAGE SECTION

Items that describe storage owned by someone else: the parameters of PROCEDURE DIVISION USING, or storage reached through a pointer. A linkage item has no storage of its own. See Subprograms, CALL and LINKAGE

None; it addresses the caller’s storage (or a BASED area) while the call is active

SCREEN SECTION

Full-screen layouts for ACCEPT and DISPLAY (ISO 2002 screen handling; GnuCOBOL)

Static description

REPORT SECTION

Report groups for the Report Writer (RD entries; ISO 1985 and 2002)

Static description; see Reports and the Report Writer

Enterprise COBOL describes the same four central sections in its DATA DIVISION overview, and has no SCREEN section. Object-oriented programs add the same sections to class definitions, factory definitions and methods (see Object-Oriented COBOL).

The program below makes the lifetime difference visible. COUNTER is called three times by LIFE.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. LIFE.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       77  WS-I                    PIC 9 VALUE 0.
       PROCEDURE DIVISION.
       MAIN-PARA.
           PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 3
               CALL "COUNTER"
           END-PERFORM
           STOP RUN.
       END PROGRAM LIFE.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. COUNTER.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       77  WS-KEPT                 PIC 9(3) VALUE 0.
       LOCAL-STORAGE SECTION.
       77  LS-FRESH                PIC 9(3) VALUE 0.
       PROCEDURE DIVISION.
       MAIN-PARA.
           ADD 1 TO WS-KEPT
           ADD 1 TO LS-FRESH
           DISPLAY "WORKING-STORAGE " WS-KEPT
               "  LOCAL-STORAGE " LS-FRESH
           GOBACK.
       END PROGRAM COUNTER.

Output:

WORKING-STORAGE 001  LOCAL-STORAGE 001
WORKING-STORAGE 002  LOCAL-STORAGE 001
WORKING-STORAGE 003  LOCAL-STORAGE 001

The WORKING-STORAGE counter keeps counting and the LOCAL-STORAGE counter starts again at its VALUE on each call. Note that LOCAL-STORAGE costs a reallocation on every call, so use it for recursive programs and re-entrant code and keep ordinary state in WORKING-STORAGE. In GnuCOBOL a program that has a LOCAL-STORAGE SECTION is treated as recursive.

The FILE SECTION in a real program

A file’s record description normally comes from a copybook placed directly under the FD, so that every program reading BOOKMAST sees the same layout. This program reads the four sample books.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. FILESEC.
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT BOOK-FILE ASSIGN TO "BOOKMAST"
               ORGANIZATION IS LINE SEQUENTIAL.
       DATA DIVISION.
       FILE SECTION.
       FD  BOOK-FILE.
           COPY BOOKREC.
       WORKING-STORAGE SECTION.
       77  WS-EOF                  PIC X VALUE "N".
           88  AT-END-OF-BOOKS     VALUE "Y".
       PROCEDURE DIVISION.
       MAIN-PARA.
           OPEN INPUT BOOK-FILE
           PERFORM UNTIL AT-END-OF-BOOKS
               READ BOOK-FILE
                   AT END SET AT-END-OF-BOOKS TO TRUE
                   NOT AT END
                       DISPLAY BOOK-ID " " BOOK-TITLE " " BOOK-COPIES
               END-READ
           END-PERFORM
           CLOSE BOOK-FILE
           STOP RUN.

Output:

000001 DATA STRUCTURES                003
000002 COBOL BASICS                   002
000003 BATCH PROCESSING               001
000004 OLD LEDGERS                    001

The SELECT clause and the FD clauses are explained on the file pages. Here the point is only that BOOK-RECORD, a level 01 entry from the copybook, sits under the FD, and so it is the record area: there is no separate declaration of the buffer.

Level numbers

A data description entry starts with a level number. It tells the compiler where the entry sits in the hierarchy.

Level Meaning

01

The record itself, the most inclusive level. It can be a group or an elementary item and must start in Area A. A level 01 item is the unit that is allocated and that COPY usually brings in.

02 to 49

Group and elementary items inside a record. Higher numbers mean less inclusive items, and the numbers need not be consecutive. They can start in Area A or Area B. A single digit may stand for 01 to 09.

66

A RENAMES entry that regroups several items of the record. Covered on REDEFINES, RENAMES and TYPEDEF.

77

An independent item: not part of any record and not subdivided. It must start in Area A, and it exists only in WORKING-STORAGE, LOCAL-STORAGE and LINKAGE. It behaves like a level 01 elementary item.

88

A condition-name attached to the value or values of the item above it. It owns no storage. Covered on VALUE, INITIALIZE and Condition Names.

A group item includes every entry that follows it until an entry with a level number less than or equal to the group’s own is met. That is the whole rule: nothing is declared as "end of group", the next entry of the same or a lower level closes it. A group has no PICTURE. An item with a PICTURE (or one of the numeric usages that implies a size) is elementary.

The record layout of BOOK-RECORD

The copybook BOOKREC describes the 60 byte book record. The figure shows each entry with its level, PICTURE, offset and length, and a proportional bar of the same bytes.

The 60-byte BOOK-RECORD with level numbers, PICTURE clauses, offsets and lengths

Offsets count from zero and are the sum of the lengths of everything before the item. The two 88 entries share the byte of BOOK-STATUS and add no storage, and the trailing FILLER pads the record to a round 60 bytes.

Which of these sizes the compiler computed can be checked with FUNCTION LENGTH.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. LAYOUT.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
           COPY BOOKREC.
       77  WS-LEN                  PIC 9(3).
       PROCEDURE DIVISION.
       MAIN-PARA.
           MOVE 1 TO BOOK-ID
           MOVE "9780000000002" TO BOOK-ISBN
           MOVE "Analytical Engines" TO BOOK-TITLE
           MOVE 7 TO BOOK-COPIES
           MOVE 24.50 TO BOOK-PRICE
           SET BOOK-ACTIVE TO TRUE
           COMPUTE WS-LEN = FUNCTION LENGTH(BOOK-RECORD)
           DISPLAY "group length      : " WS-LEN
           COMPUTE WS-LEN = FUNCTION LENGTH(BOOK-ID)
           DISPLAY "BOOK-ID length    : " WS-LEN
           COMPUTE WS-LEN = FUNCTION LENGTH(BOOK-TITLE)
           DISPLAY "BOOK-TITLE length : " WS-LEN
           COMPUTE WS-LEN = FUNCTION LENGTH(BOOK-PRICE)
           DISPLAY "BOOK-PRICE length : " WS-LEN
           DISPLAY "[" BOOK-RECORD "]"
           STOP RUN.

Output:

group length      : 060
BOOK-ID length    : 006
BOOK-TITLE length : 030
BOOK-PRICE length : 006
[0000019780000000002Analytical Engines            007002450A ]

The sum of the elementary lengths (6 + 13 + 30 + 3 + 6 + 1 + 1) is 60. The price shows as 002450 because PIC 9(4)V99 stores six digits and the decimal point is only implied by the V. Nothing in the record tells a reader where the point is except the picture, which is why the copybook and the picture are the contract between programs. See The PICTURE Clause.

Non-consecutive and mixed level numbers

Level numbers only need to increase with depth. A program may use 05, 10, 20 as it likes, and two siblings may even be numbered differently. This example uses the Circulation loan key with a non-consecutive 10/20 pair, an unnamed FILLER, a 77 item and a 66 regrouping.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. LEVELS.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       77  WS-LEN                  PIC 9(3).
       01  LOAN-LINE.
           05  LINE-KEY.
               10  LINE-MEMBER     PIC 9(6) VALUE 100.
               10  LINE-BOOK       PIC 9(6) VALUE 1.
           05  LINE-DATE.
               20  LINE-YEAR       PIC 9(4) VALUE 2026.
               20  LINE-MONTH      PIC 99   VALUE 10.
               20  LINE-DAY        PIC 99   VALUE 20.
           05  FILLER              PIC X(2) VALUE SPACES.
           05  LINE-TYPE           PIC X    VALUE "O".
               88  LINE-CHECKOUT   VALUE "O".
       66  LINE-WHO-WHAT RENAMES LINE-MEMBER THRU LINE-BOOK.
       PROCEDURE DIVISION.
       MAIN-PARA.
           COMPUTE WS-LEN = FUNCTION LENGTH(LOAN-LINE)
           DISPLAY "LOAN-LINE (" WS-LEN "): [" LOAN-LINE "]"
           COMPUTE WS-LEN = FUNCTION LENGTH(LINE-DATE)
           DISPLAY "LINE-DATE (" WS-LEN "): [" LINE-DATE "]"
           DISPLAY "renamed: [" LINE-WHO-WHAT "]"
           IF LINE-CHECKOUT
               DISPLAY "checkout"
           END-IF
           STOP RUN.

Output:

LOAN-LINE (023): [00010000000120261020  O]
LINE-DATE (008): [20261020]
renamed: [000100000001]
checkout

The Enterprise COBOL manual also shows siblings given different numbers at the same depth (05 EMPLOYEE-NAME next to 04 EMPLOYEE-ADDRESS, then children numbered 10 and 08) and says the compiler renumbers the levels relatively. GnuCOBOL 3.2 does not accept that style. The following program, a direct transcription of the idea, is deliberately non-portable.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. MIXED.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  LOAN-LINE.
           05  LINE-KEY.
               10  LINE-MEMBER     PIC 9(6) VALUE 100.
               10  LINE-BOOK       PIC 9(6) VALUE 1.
           04  LINE-DATE.
               08  LINE-YEAR       PIC 9(4) VALUE 2026.
               08  LINE-MONTH      PIC 99   VALUE 10.
               08  LINE-DAY        PIC 99   VALUE 20.
       PROCEDURE DIVISION.
       MAIN-PARA.
           DISPLAY LINE-YEAR "-" LINE-MONTH "-" LINE-DAY
           STOP RUN.

Output with the default dialect (an error):

mixed.cob:9: error: no previous data item of level 04
    7 |                10  LINE-MEMBER     PIC 9(6) VALUE 100.
    8 |                10  LINE-BOOK       PIC 9(6) VALUE 1.
    9 >            04  LINE-DATE.
   10 |                08  LINE-YEAR       PIC 9(4) VALUE 2026.
   11 |                08  LINE-MONTH      PIC 99   VALUE 10.

Under -std=ibm the same text is reduced to a warning and the program runs:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. MIXED.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  LOAN-LINE.
           05  LINE-KEY.
               10  LINE-MEMBER     PIC 9(6) VALUE 100.
               10  LINE-BOOK       PIC 9(6) VALUE 1.
           04  LINE-DATE.
               08  LINE-YEAR       PIC 9(4) VALUE 2026.
               08  LINE-MONTH      PIC 99   VALUE 10.
               08  LINE-DAY        PIC 99   VALUE 20.
       PROCEDURE DIVISION.
       MAIN-PARA.
           DISPLAY LINE-YEAR "-" LINE-MONTH "-" LINE-DAY
           STOP RUN.

Output with -std=ibm (the warning is still printed):

2026-10-20
mixed.cob:9: warning: no previous data item of level 04 [-Wothers]
    7 |                10  LINE-MEMBER     PIC 9(6) VALUE 100.
    8 |                10  LINE-BOOK       PIC 9(6) VALUE 1.
    9 >            04  LINE-DATE.
   10 |                08  LINE-YEAR       PIC 9(4) VALUE 2026.
   11 |                08  LINE-MONTH      PIC 99   VALUE 10.

Write consecutive, consistently numbered siblings. Skipping numbers (05, 10, 15) leaves room to insert a level later and is portable. Using different numbers for siblings is legal on z/OS but gives a warning or error elsewhere and gains nothing.

Level numbers beyond the legal set are plain syntax errors. A 50 level is not a level at all, and GnuCOBOL’s resynchronisation produces a cascade, of which the first line is the useful one.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. BADLEVEL.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  LOAN-LINE.
           05  LINE-KEY            PIC 9(6).
       50  TOO-DEEP                PIC X.
       01  LOAN-LINE-2.
               10  LINE-KEY        PIC 9(6).
       PROCEDURE DIVISION.
       MAIN-PARA.
           STOP RUN.

Output (deliberately wrong source; the first line is the real error):

badlevel.cob:7: error: PROCEDURE DIVISION header missing
    5 |        01  LOAN-LINE.
    6 |            05  LINE-KEY            PIC 9(6).
    7 >        50  TOO-DEEP                PIC X.
    8 |        01  LOAN-LINE-2.
    9 |                10  LINE-KEY        PIC 9(6).
badlevel.cob:7: error: syntax error, unexpected Identifier
badlevel.cob:8: error: syntax error, unexpected Identifier, expecting SECTION or .
    6 |            05  LINE-KEY            PIC 9(6).
    7 |        50  TOO-DEEP                PIC X.
    8 >        01  LOAN-LINE-2.
    9 |                10  LINE-KEY        PIC 9(6).
   10 |        PROCEDURE DIVISION.
badlevel.cob:8: note: unknown statement '01'
badlevel.cob:9: error: syntax error, unexpected Identifier, expecting SECTION or .
    7 |        50  TOO-DEEP                PIC X.
    8 |        01  LOAN-LINE-2.
    9 >                10  LINE-KEY        PIC 9(6).
   10 |        PROCEDURE DIVISION.
   11 |        MAIN-PARA.
badlevel.cob:9: note: unknown statement '10'
badlevel.cob:10: error: syntax error, unexpected PROCEDURE
    8 |        01  LOAN-LINE-2.
    9 |                10  LINE-KEY        PIC 9(6).
   10 >        PROCEDURE DIVISION.
   11 |        MAIN-PARA.
   12 |            STOP RUN.

Group items are just bytes

A group item has no type of its own. In MOVE and in comparisons it is treated as one alphanumeric string, the concatenation of its subordinates exactly as they are stored. No editing and no conversion takes place, so a numeric elementary item inside the group moves as its stored digit characters, not as a number. The Enterprise COBOL manual calls this an alphanumeric group and says the group is processed as if its usage were DISPLAY, whatever the usage of the items inside it. The exception is MOVE CORRESPONDING and the other CORRESPONDING forms, which look inside and handle the subordinate items one by one.

That makes a group move a block copy of bytes. It is the way a whole record is read into a work area, saved, restored or written, and it is also the reason a group move can corrupt a numeric field: moving spaces to a group overwrites packed or zoned digits with blanks, and the numeric fields inside it are no longer numeric.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. GMOVE.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
           COPY BOOKREC.
       01  BOOK-IMAGE              PIC X(60).
       01  BOOK-SNAPSHOT.
           05  SNAP-ID             PIC X(6).
           05  SNAP-REST           PIC X(54).
       PROCEDURE DIVISION.
       MAIN-PARA.
           MOVE 42 TO BOOK-ID
           MOVE "9780000000042" TO BOOK-ISBN
           MOVE "Notes on Compilers" TO BOOK-TITLE
           MOVE 3 TO BOOK-COPIES
           MOVE 19.99 TO BOOK-PRICE
           SET BOOK-WITHDRAWN TO TRUE
           MOVE BOOK-RECORD TO BOOK-IMAGE
           MOVE BOOK-IMAGE TO BOOK-SNAPSHOT
           DISPLAY "image   : [" BOOK-IMAGE "]"
           DISPLAY "snap id : [" SNAP-ID "]"
           MOVE SPACES TO BOOK-RECORD
           DISPLAY "id after MOVE SPACES to the group: [" BOOK-ID "]"
           MOVE BOOK-IMAGE TO BOOK-RECORD
           DISPLAY "restored id, price: " BOOK-ID " " BOOK-PRICE
           STOP RUN.

Output:

image   : [0000429780000000042Notes on Compilers            003001999W ]
snap id : [000042]
id after MOVE SPACES to the group: [      ]
restored id, price: 000042 0019.99

MOVE SPACES TO BOOK-RECORD filled BOOK-ID with blanks, a value that is not a valid number, and restoring the saved image made the numbers valid again. The rules of MOVE itself, including what happens when the sizes differ, are on MOVE and Data Movement. Enterprise COBOL also has national and UTF-8 groups through GROUP-USAGE, covered on National, UTF-8 and Code Pages.

FILLER

FILLER is the name given to an item that the program never refers to by name: padding, reserved bytes and the unused tail of a record. The word is optional. An entry with a level number and a PICTURE and no name is treated as FILLER. BOOKREC ends with one, so a future field can be added without moving the file’s record length.

  • FILLER has to be the first word after the level number.

  • It cannot be used with a condition-name (level 88), and cannot be referenced.

  • MOVE CORRESPONDING, ADD CORRESPONDING and SUBTRACT CORRESPONDING ignore FILLER items.

  • INITIALIZE skips elementary FILLER items, unless the FILLER phrase is given in Enterprise COBOL (see VALUE, INITIALIZE and Condition Names).

  • A FILLER may carry a VALUE. That is how print lines and headings are built, so the literal text sits in the layout.

    == Qualification: OF, IN and

    The same name may be declared in several records, for example BOOK-ID in the master record and in a work copy. A reference must then say which one by naming a higher-level item of the hierarchy, a qualifier.

Form Notes

BOOK-ID OF OLD-BOOK, BOOK-ID IN OLD-BOOK

Low-to-high qualification: the name, then its parents going upward. OF and IN are interchangeable. Supported by every compiler.

OLD-BOOK::BOOK-ID

High-to-low qualification with the :: operator, parents first. New in Enterprise COBOL 6.5. The ISO standard and GnuCOBOL 3.2 do not have it.

Qualifiers must belong to the same hierarchy. You only need enough of them to make the reference unique; extra ones are allowed but redundant, except in a REDEFINES clause, where the name must not be qualified. Level 01 and level 77 items cannot be qualified, so they must have unique names in the program.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. QUAL.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  OLD-BOOK.
           05  ID-FIELDS.
               10  BOOK-ID         PIC 9(6) VALUE 1.
               10  BOOK-COPIES     PIC 9(3) VALUE 5.
       01  NEW-BOOK.
           05  ID-FIELDS.
               10  BOOK-ID         PIC 9(6) VALUE 2.
               10  BOOK-COPIES     PIC 9(3) VALUE 9.
       PROCEDURE DIVISION.
       MAIN-PARA.
           DISPLAY BOOK-ID OF ID-FIELDS OF OLD-BOOK
           DISPLAY BOOK-ID IN NEW-BOOK
           DISPLAY BOOK-COPIES OF OLD-BOOK " " BOOK-COPIES OF NEW-BOOK
           MOVE BOOK-COPIES OF NEW-BOOK TO BOOK-COPIES OF OLD-BOOK
           DISPLAY BOOK-COPIES IN ID-FIELDS IN OLD-BOOK
           STOP RUN.

Output:

000001
000002
005 009
009

An ambiguous reference is a compile error, and the diagnostic lists every candidate. The program below is deliberately wrong: line 11 does not qualify, and line 12 uses the 6.5 :: form, which GnuCOBOL 3.2 rejects.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. QUALBAD.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  OLD-BOOK.
           05  BOOK-ID             PIC 9(6) VALUE 1.
       01  NEW-BOOK.
           05  BOOK-ID             PIC 9(6) VALUE 2.
       PROCEDURE DIVISION.
       MAIN-PARA.
           DISPLAY BOOK-ID
           DISPLAY OLD-BOOK::BOOK-ID
           STOP RUN.

Output (deliberately wrong source):

qualbad.cob: in paragraph 'MAIN-PARA':
qualbad.cob:11: error: 'BOOK-ID' is ambiguous; needs qualification
    9 |        PROCEDURE DIVISION.
   10 |        MAIN-PARA.
   11 >            DISPLAY BOOK-ID
   12 |            DISPLAY OLD-BOOK::BOOK-ID
   13 |            STOP RUN.
qualbad.cob:6: note: 'BOOK-ID IN OLD-BOOK' defined here
    4 |        WORKING-STORAGE SECTION.
    5 |        01  OLD-BOOK.
    6 >            05  BOOK-ID             PIC 9(6) VALUE 1.
    7 |        01  NEW-BOOK.
    8 |            05  BOOK-ID             PIC 9(6) VALUE 2.
qualbad.cob:8: note: 'BOOK-ID IN NEW-BOOK' defined here
    6 |            05  BOOK-ID             PIC 9(6) VALUE 1.
    7 |        01  NEW-BOOK.
    8 >            05  BOOK-ID             PIC 9(6) VALUE 2.
    9 |        PROCEDURE DIVISION.
   10 |        MAIN-PARA.
qualbad.cob:12: error: syntax error, unexpected :
   10 |        MAIN-PARA.
   11 |            DISPLAY BOOK-ID
   12 >            DISPLAY OLD-BOOK::BOOK-ID
   13 |            STOP RUN.
   14 | <EOF>

In Enterprise COBOL 6.5 the same hierarchy A / B / C can be written C OF B OF A or A::B::C, and a partial form such as B::C is fine when it is unique. This is z/OS only and not run here. The compiler option QUALIFY(EXTEND) also lets a reference count as unique when only one fully qualified name matches the qualifiers given, even if the same words also partially match another item; the default QUALIFY(COMPAT) keeps the old rule. In a portable program keep using OF, which both compilers and every earlier release accept.

Good naming reduces the need for qualification. The Circulation copybooks prefix their fields (BOOK-, MEMBER-, LOAN-) so they can be copied into the same program without clashes. When the same copybook must be included twice, use COPY ... REPLACING (see Copybooks and REPLACE) instead of qualifying every use.

GLOBAL and EXTERNAL

By default a data item belongs to one program. Two clauses extend that.

EXTERNAL

The item is shared by every program of the run unit that declares it with the same name. All declarations must describe the same storage. It can only be coded on level 01 entries in WORKING-STORAGE (and on file descriptions), and it takes no VALUE. It is the COBOL way of sharing a common area between separately compiled programs without passing parameters. The EXTERNAL clause does not make the name global.

GLOBAL

The item is visible to the programs contained inside the program that declares it, so nested programs can use it. A contained program that declares the same name itself gets its own item. GLOBAL is about visibility from nested programs, and does not share storage between separate programs.

Both need a name (FILLER is not allowed), and both are written on the entry after the name, in the form 01 name EXTERNAL. or 01 name GLOBAL PIC .... The program below declares both. SHARED sets the run totals, REPORTER, a separate program, reads them through its own EXTERNAL declaration, and NESTED uses the global batch date.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. SHARED.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  RUN-TOTALS EXTERNAL.
           05  TOT-CHECKOUTS       PIC 9(4).
           05  TOT-RETURNS         PIC 9(4).
       01  BATCH-DATE GLOBAL       PIC 9(8) VALUE 20261020.
       PROCEDURE DIVISION.
       MAIN-PARA.
           MOVE 3 TO TOT-CHECKOUTS
           MOVE 1 TO TOT-RETURNS
           CALL "REPORTER"
           CALL "NESTED"
           STOP RUN.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. NESTED.
       PROCEDURE DIVISION.
       MAIN-PARA.
           DISPLAY "nested sees GLOBAL date " BATCH-DATE
           EXIT PROGRAM.
       END PROGRAM NESTED.

       END PROGRAM SHARED.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. REPORTER.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  RUN-TOTALS EXTERNAL.
           05  TOT-CHECKOUTS       PIC 9(4).
           05  TOT-RETURNS         PIC 9(4).
       PROCEDURE DIVISION.
       MAIN-PARA.
           DISPLAY "reporter sees EXTERNAL " TOT-CHECKOUTS " "
               TOT-RETURNS
           GOBACK.
       END PROGRAM REPORTER.

Output:

reporter sees EXTERNAL 0003 0001
nested sees GLOBAL date 20261020

GLOBAL and EXTERNAL hide data flow, which is a maintenance cost: the shared area is a hidden interface. Prefer parameters passed with CALL ... USING (see Subprograms, CALL and LINKAGE) and keep these for genuinely run-wide state. Several special registers are themselves GLOBAL: in GnuCOBOL RETURN-CODE, SORT-RETURN, TALLY and the JSON and XML status registers are defined that way.

BASED items and dynamic storage

A BASED item is described like any other record but gets no storage at compile time. You obtain storage while the program runs and attach the description to it. It was added in the 2002 standard, and it is supported in GnuCOBOL 3.2. ALLOCATE creates the storage, FREE releases it.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. BASED2.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  MEMBER-RECORD BASED.
           05  MEMBER-ID           PIC 9(6).
           05  MEMBER-NAME         PIC X(30).
       PROCEDURE DIVISION.
       MAIN-PARA.
           ALLOCATE MEMBER-RECORD INITIALIZED
           MOVE 100 TO MEMBER-ID
           MOVE "Ada Lovelace" TO MEMBER-NAME
           DISPLAY MEMBER-ID " " MEMBER-NAME
           FREE ADDRESS OF MEMBER-RECORD
           STOP RUN.

Output:

000100 Ada Lovelace

The BASED clause is the data side of dynamic memory. The same idea without the clause is a LINKAGE SECTION record whose address is set with SET ADDRESS OF. The pointer is needed in order to free the storage later.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. BASED3.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  MEMBER-PTR              USAGE POINTER.
       01  WS-SIZE                 PIC 9(4) COMP-5.
       LINKAGE SECTION.
           COPY MEMBREC.
       PROCEDURE DIVISION.
       MAIN-PARA.
           MOVE LENGTH OF MEMBER-RECORD TO WS-SIZE
           ALLOCATE WS-SIZE CHARACTERS INITIALIZED RETURNING MEMBER-PTR
           SET ADDRESS OF MEMBER-RECORD TO MEMBER-PTR
           MOVE 100 TO MEMBER-ID
           MOVE "Ada Lovelace" TO MEMBER-NAME
           SET MEMBER-ACTIVE TO TRUE
           DISPLAY MEMBER-ID " " MEMBER-NAME " " MEMBER-STATUS
           FREE MEMBER-PTR
           STOP RUN.

Output:

000100 Ada Lovelace                   A

Allocating a record that is not BASED is an error, and the diagnostic is precise.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. BASEDEX.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  MEMBER-PTR              USAGE POINTER.
       LINKAGE SECTION.
           COPY MEMBREC.
       PROCEDURE DIVISION.
       MAIN-PARA.
           ALLOCATE MEMBER-RECORD INITIALIZED RETURNING MEMBER-PTR
           MOVE 100 TO MEMBER-ID
           MOVE "Ada Lovelace" TO MEMBER-NAME
           SET MEMBER-ACTIVE TO TRUE
           DISPLAY MEMBER-ID " " MEMBER-NAME " " MEMBER-STATUS
           FREE MEMBER-PTR
           STOP RUN.

Output (deliberately wrong source):

based.cob: in paragraph 'MAIN-PARA':
based.cob:10: error: target of ALLOCATE must have BASED clause
    8 |        PROCEDURE DIVISION.
    9 |        MAIN-PARA.
   10 >            ALLOCATE MEMBER-RECORD INITIALIZED RETURNING MEMBER-PTR
   11 |            MOVE 100 TO MEMBER-ID
   12 |            MOVE "Ada Lovelace" TO MEMBER-NAME

The Enterprise COBOL 6.5 Language Reference has no BASED clause. On z/OS the usual way is a LINKAGE SECTION item whose address is set with SET ADDRESS OF over storage obtained from Language Environment services (z/OS; not run here). Pointers, ALLOCATE, FREE and the Language Environment services are on Pointers and Dynamic Storage.

Dialect and standards summary

Feature ISO/IEC 1989:2023 GnuCOBOL 3.2 Enterprise COBOL 6.5

WORKING-STORAGE, FILE, LINKAGE, LOCAL-STORAGE

Yes

Yes

Yes

SCREEN SECTION, REPORT SECTION

Yes (screen: 2002; report: 1985)

Yes

No SCREEN SECTION; Report Writer not checked here

OF / IN qualification

Yes

Yes

Yes

:: high-to-low qualification

No

No (syntax error)

Yes, new in 6.5

GLOBAL, EXTERNAL

Yes

Yes

Yes

BASED, ALLOCATE, FREE

Yes (2002)

Yes

Not in the 6.5 Language Reference

Unequal numbering of siblings

Not checked

Error; warning under -std=ibm

Accepted, relative renumbering

The comparison of dialects as a whole is on COBOL Compilers and Dialects.

Where the book is outdated

Modern Mainframe Development (Taulli, 2022) introduces level numbers 01, 77 and 88 and the layout of records. That part still holds. What it does not cover is anything added since the 2002 standard: BASED storage, the LOCAL-STORAGE section as the usual way to get a fresh set of variables, and the 6.5 :: qualification. It has no coverage of the 2002-era features that differ between compilers, so check the dialect table above before reusing its examples on GnuCOBOL.