Skip to main content

Cobol

Welcome to COBOL

COBOL (Common Business-Oriented Language) is a high-level programming language designed for business applications. Developed in 1959, COBOL has been a cornerstone of business, finance, and administrative systems for decades.

Known for its readability and self-documenting nature, COBOL uses English-like syntax that makes it accessible to non-programmers. Despite its age, COBOL remains critical to many legacy systems in banking, insurance, government, and healthcare, processing billions of transactions daily.

Introduction to COBOL

How to set up a COBOL development environment and write your first "Hello, World!" program.

COBOL is known for its structured, readable syntax and division-based organization. Setting up a COBOL environment varies by platform.

Step 1: Install a COBOL Compiler

  1. Windows
    Install GnuCOBOL (formerly OpenCOBOL) or Micro Focus Visual COBOL. For GnuCOBOL, download from the official website and add to your PATH.

  2. Linux
    Use your distribution's package manager. For Ubuntu/Debian:

    sudo apt install gnucobol
  3. Mainframe
    COBOL is typically pre-installed on IBM mainframes (z/OS).

Step 2: Verify Installation

Open a terminal or command prompt and type:

cobc --version

This should display the installed compiler version.

Step 3: Write and Compile Your First COBOL Program

  1. Create a file named hello.cbl with the following content:

    IDENTIFICATION DIVISION.
      PROGRAM-ID. HELLO-WORLD.
      PROCEDURE DIVISION.
          DISPLAY 'Hello, World!'.
          STOP RUN.
  2. Compile the program:

    cobc -x hello.cbl
  3. Run the executable:

    ./hello   # On Linux
      hello.exe   # On Windows

    You should see the output: Hello, World!

Congratulations! You have successfully set up a COBOL environment and run your first program. 🎉

COBOL Syntax Basics

COBOL syntax is designed to be readable and self-documenting. Understanding the basic syntax is crucial for writing correct COBOL programs.

1. Basic Structure of a COBOL Program

Every COBOL program has four main divisions:

IDENTIFICATION DIVISION.
  PROGRAM-ID. YOUR-PROGRAM-NAME.
  AUTHOR. YOUR-NAME.

  ENVIRONMENT DIVISION.
  CONFIGURATION SECTION.
  SOURCE-COMPUTER. IBM-370.
  OBJECT-COMPUTER. IBM-370.

  DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-VARIABLE PIC X(10).

  PROCEDURE DIVISION.
  MAIN-PARAGRAPH.
      DISPLAY 'Program started'.
      STOP RUN.

2. Coding Rules

COBOL has specific coding rules:

* Column 1-6: Sequence numbers (optional)
  * Column 7: Indicator area
  *    - (space): Regular line
  *    - *: Comment line
  *    - /: Comment line with page eject
  *    - -: Continuation line
  * Column 8-72: Program text
  * Column 73-80: Identification (optional)

3. Periods and Scope Terminators

COBOL uses periods to terminate statements and scope:

IF WS-COUNT > 10 THEN
      DISPLAY 'Count is greater than 10'
  ELSE
      DISPLAY 'Count is 10 or less'
  END-IF.

4. Case Insensitivity

COBOL is generally case-insensitive:

DISPLAY 'Hello'  *> Same as display 'Hello'
  MOVE 10 TO COUNT *> Same as move 10 to count

Conclusion

Understanding COBOL syntax is essential for writing correct programs. Key takeaways include:

  • COBOL programs are organized into four divisions
  • Specific column rules must be followed
  • Periods terminate statements and paragraphs
  • COBOL is generally case-insensitive
  • Comments start with asterisk (*) in column 7

Output with DISPLAY

The DISPLAY statement in COBOL is used to display output on the screen or other output devices. It is one of the most commonly used features for basic output and debugging.

1. Basic DISPLAY Usage

The simplest way to use DISPLAY is with literal strings:

IDENTIFICATION DIVISION.
  PROGRAM-ID. DISPLAY-DEMO.
  PROCEDURE DIVISION.
      DISPLAY 'Hello, World!'.
      DISPLAY 42.
      STOP RUN.

2. Displaying Multiple Values

You can display multiple values in one statement:

DISPLAY 'Hello' ' ' 'COBOL'.  *> Outputs: Hello COBOL

3. Displaying Variables

You can display variables along with literals:

IDENTIFICATION DIVISION.
  PROGRAM-ID. DISPLAY-VARS.
  DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-NAME PIC X(10) VALUE 'Alice'.
  01 WS-AGE PIC 99 VALUE 25.
  PROCEDURE DIVISION.
      DISPLAY 'Name: ' WS-NAME ', Age: ' WS-AGE.
      STOP RUN.

4. Formatting Output

COBOL provides various ways to format output:

DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-AMOUNT PIC 9(5)V99 VALUE 12345.67.
  01 WS-DATE PIC 99/99/9999 VALUE 12032024.
  PROCEDURE DIVISION.
      DISPLAY 'Amount: $' WS-AMOUNT.
      DISPLAY 'Date: ' WS-DATE.
      STOP RUN.

5. Advanced Display Features

* Display with position and line control
  DISPLAY 'Line 1' LINE 1 COLUMN 1.
  DISPLAY 'Line 2' LINE 2 COLUMN 1.

  * Display with erase
  DISPLAY 'Clearing screen' WITH BLANK SCREEN.

  * Display with attribute
  DISPLAY 'Highlighted' WITH HIGHLIGHT.

Conclusion

The DISPLAY statement is a fundamental tool for output in COBOL. Key points:

  • Use DISPLAY for simple output
  • Can display literals, variables, or combinations
  • Supports basic formatting and positioning
  • Essential for debugging and user interaction

Arithmetic Operators in COBOL

COBOL provides arithmetic operators for mathematical calculations. These operators work with numeric data types and fields.

Basic Arithmetic Operations

IDENTIFICATION DIVISION.
  PROGRAM-ID. ARITHMETIC-DEMO.
  DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-A PIC 99 VALUE 15.
  01 WS-B PIC 99 VALUE 4.
  01 WS-RESULT PIC 999.
  PROCEDURE DIVISION.
      COMPUTE WS-RESULT = WS-A + WS-B.
      DISPLAY 'A + B = ' WS-RESULT.

      COMPUTE WS-RESULT = WS-A - WS-B.
      DISPLAY 'A - B = ' WS-RESULT.

      COMPUTE WS-RESULT = WS-A * WS-B.
      DISPLAY 'A * B = ' WS-RESULT.

      COMPUTE WS-RESULT = WS-A / WS-B.
      DISPLAY 'A / B = ' WS-RESULT.

      STOP RUN.

Arithmetic Verbs

DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-NUM1 PIC 999 VALUE 100.
  01 WS-NUM2 PIC 999 VALUE 50.
  01 WS-RESULT PIC 999.
  PROCEDURE DIVISION.
      ADD WS-NUM1 TO WS-NUM2 GIVING WS-RESULT.
      DISPLAY 'ADD: ' WS-RESULT.

      SUBTRACT WS-NUM2 FROM WS-NUM1 GIVING WS-RESULT.
      DISPLAY 'SUBTRACT: ' WS-RESULT.

      MULTIPLY WS-NUM1 BY 2 GIVING WS-RESULT.
      DISPLAY 'MULTIPLY: ' WS-RESULT.

      DIVIDE WS-NUM1 BY 2 GIVING WS-RESULT.
      DISPLAY 'DIVIDE: ' WS-RESULT.

      STOP RUN.

Common Pitfalls

  • Ensure numeric fields have proper PIC clauses
  • Watch for decimal alignment in computations
  • Use COMPUTE for complex expressions
  • Handle potential overflow conditions

Comparison Operators in COBOL

Comparison operators compare two values and determine the relationship between them. These are essential for conditional statements.

Comparison Operators

IDENTIFICATION DIVISION.
  PROGRAM-ID. COMPARE-DEMO.
  DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-X PIC 99 VALUE 7.
  01 WS-Y PIC 99 VALUE 10.
  PROCEDURE DIVISION.
      IF WS-X = WS-Y
          DISPLAY 'X equals Y'
      ELSE
          DISPLAY 'X not equal to Y'
      END-IF.

      IF WS-X > WS-Y
          DISPLAY 'X greater than Y'
      ELSE
          DISPLAY 'X not greater than Y'
      END-IF.

      IF WS-X < WS-Y
          DISPLAY 'X less than Y'
      ELSE
          DISPLAY 'X not less than Y'
      END-IF.

      IF WS-X >= 7
          DISPLAY 'X greater than or equal to 7'
      END-IF.

      STOP RUN.

String Comparisons

DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-NAME1 PIC X(10) VALUE 'ALICE'.
  01 WS-NAME2 PIC X(10) VALUE 'BOB'.
  PROCEDURE DIVISION.
      IF WS-NAME1 = WS-NAME2
          DISPLAY 'Names are equal'
      ELSE
          DISPLAY 'Names are different'
      END-IF.

      IF WS-NAME1 > WS-NAME2
          DISPLAY WS-NAME1 ' comes after ' WS-NAME2
      ELSE
          DISPLAY WS-NAME1 ' comes before ' WS-NAME2
      END-IF.

      STOP RUN.

Common Pitfalls

  • Alphanumeric comparisons use collating sequence
  • Numeric comparisons require proper numeric fields
  • Be careful with signed numbers in comparisons
  • Use proper scope terminators with IF statements

Logical Operators in COBOL

Logical operators combine multiple conditions. COBOL provides AND, OR, and NOT operators for building complex conditions.

Logical Operators

IDENTIFICATION DIVISION.
  PROGRAM-ID. LOGICAL-DEMO.
  DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-AGE PIC 99.
  01 WS-HAS-LICENSE PIC X VALUE 'N'.
      88 HAS-LICENSE VALUE 'Y'.
      88 NO-LICENSE VALUE 'N'.
  PROCEDURE DIVISION.
      MOVE 25 TO WS-AGE.
      MOVE 'Y' TO WS-HAS-LICENSE.

      IF WS-AGE >= 18 AND HAS-LICENSE
          DISPLAY 'Can drive legally'
      ELSE
          DISPLAY 'Cannot drive'
      END-IF.

      IF WS-AGE < 18 OR NO-LICENSE
          DISPLAY 'Needs supervision or license'
      END-IF.

      IF NOT (WS-AGE >= 21)
          DISPLAY 'Not old enough to drink'
      END-IF.

      STOP RUN.

Complex Conditions

DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-SCORE PIC 999.
  01 WS-GRADE PIC X.
      88 A-GRADE VALUE 'A'.
      88 B-GRADE VALUE 'B'.
      88 C-GRADE VALUE 'C'.
      88 FAILING VALUE 'D', 'F'.
  PROCEDURE DIVISION.
      MOVE 85 TO WS-SCORE.

      EVALUATE TRUE
          WHEN WS-SCORE >= 90
              MOVE 'A' TO WS-GRADE
          WHEN WS-SCORE >= 80 AND WS-SCORE < 90
              MOVE 'B' TO WS-GRADE
          WHEN WS-SCORE >= 70 AND WS-SCORE < 80
              MOVE 'C' TO WS-GRADE
          WHEN OTHER
              MOVE 'F' TO WS-GRADE
      END-EVALUATE.

      DISPLAY 'Score: ' WS-SCORE ', Grade: ' WS-GRADE.

      STOP RUN.

Common Pitfalls

  • Use parentheses to clarify operator precedence
  • Be careful with NOT operator placement
  • 88-level conditions provide readable alternatives
  • EVALUATE can be cleaner than nested IF statements

Assignment Operations in COBOL

COBOL uses various verbs for assigning values to variables. The most common are MOVE, COMPUTE, and INITIALIZE.

MOVE Statement

IDENTIFICATION DIVISION.
  PROGRAM-ID. ASSIGNMENT-DEMO.
  DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-NAME PIC X(20).
  01 WS-AGE PIC 99.
  01 WS-SALARY PIC 9(5)V99.
  01 WS-ACTIVE PIC X.
  PROCEDURE DIVISION.
      MOVE 'John Smith' TO WS-NAME.
      MOVE 30 TO WS-AGE.
      MOVE 50000.50 TO WS-SALARY.
      MOVE 'Y' TO WS-ACTIVE.

      DISPLAY 'Name: ' WS-NAME.
      DISPLAY 'Age: ' WS-AGE.
      DISPLAY 'Salary: ' WS-SALARY.
      DISPLAY 'Active: ' WS-ACTIVE.

      STOP RUN.

COMPUTE Statement

DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-BASE-SALARY PIC 9(5)V99 VALUE 50000.00.
  01 WS-BONUS PIC 9(5)V99 VALUE 5000.00.
  01 WS-TOTAL-SALARY PIC 9(6)V99.
  01 WS-TAX-RATE PIC V999 VALUE .250.
  01 WS-TAX-AMOUNT PIC 9(5)V99.
  PROCEDURE DIVISION.
      COMPUTE WS-TOTAL-SALARY = 
          WS-BASE-SALARY + WS-BONUS.

      COMPUTE WS-TAX-AMOUNT = 
          WS-TOTAL-SALARY * WS-TAX-RATE.

      DISPLAY 'Total Salary: ' WS-TOTAL-SALARY.
      DISPLAY 'Tax Amount: ' WS-TAX-AMOUNT.

      STOP RUN.

INITIALIZE Statement

DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-CUSTOMER-RECORD.
     05 WS-CUST-NAME PIC X(30).
     05 WS-CUST-AGE PIC 99.
     05 WS-CUST-BALANCE PIC 9(5)V99.
     05 WS-CUST-ACTIVE PIC X.
  PROCEDURE DIVISION.
      *> Set some values
      MOVE 'Alice Johnson' TO WS-CUST-NAME.
      MOVE 35 TO WS-CUST-AGE.
      MOVE 1250.75 TO WS-CUST-BALANCE.
      MOVE 'Y' TO WS-CUST-ACTIVE.

      DISPLAY 'Before INITIALIZE: ' WS-CUSTOMER-RECORD.

      INITIALIZE WS-CUSTOMER-RECORD.

      DISPLAY 'After INITIALIZE: ' WS-CUSTOMER-RECORD.

      STOP RUN.

Common Pitfalls

  • MOVE follows alphanumeric or numeric rules based on receiving field
  • COMPUTE allows complex expressions but requires proper data types
  • INITIALIZE sets fields to their type-appropriate initial values
  • Watch for truncation when moving larger values to smaller fields

Numeric Data Types in COBOL

COBOL provides various numeric data types with different storage and display characteristics. Understanding these is crucial for proper data handling.

Basic Numeric Types

IDENTIFICATION DIVISION.
  PROGRAM-ID. NUMERIC-TYPES.
  DATA DIVISION.
  WORKING-STORAGE SECTION.
  *> Display numbers
  01 WS-INTEGER PIC 9(5) VALUE 12345.
  01 WS-DECIMAL PIC 9(5)V99 VALUE 12345.67.
  01 WS-SIGNED-NUM PIC S9(5) VALUE -12345.
  01 WS-EDITED-NUM PIC ZZZ,ZZ9.99.

  *> Computational numbers (for arithmetic)
  01 WS-COMP-NUM PIC 9(5) COMP VALUE 12345.
  01 WS-COMP-3-NUM PIC 9(5) COMP-3 VALUE 12345.
  PROCEDURE DIVISION.
      DISPLAY 'Integer: ' WS-INTEGER.
      DISPLAY 'Decimal: ' WS-DECIMAL.
      DISPLAY 'Signed: ' WS-SIGNED-NUM.

      MOVE WS-DECIMAL TO WS-EDITED-NUM.
      DISPLAY 'Edited: ' WS-EDITED-NUM.

      DISPLAY 'COMP: ' WS-COMP-NUM.
      DISPLAY 'COMP-3: ' WS-COMP-3-NUM.

      STOP RUN.

Numeric Editing

DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-AMOUNT PIC 9(6)V99 VALUE 123456.78.
  01 WS-EDIT-FIELDS.
     05 WS-BLANK-ZERO PIC ZZZ,ZZ9.99.
     05 WS-CURRENCY PIC $$,$$9.99.
     05 WS-FIXED-DEC PIC 999999.99.
     05 WS-LEADING-ASTER PIC ****9.99.
     05 WS-CREDIT-DEBIT PIC +++,++9.99.
     05 WS-NEGATIVE PIC ---,---.99.
  PROCEDURE DIVISION.
      MOVE WS-AMOUNT TO WS-BLANK-ZERO.
      DISPLAY 'Blank zero: ' WS-BLANK-ZERO.

      MOVE WS-AMOUNT TO WS-CURRENCY.
      DISPLAY 'Currency: ' WS-CURRENCY.

      MOVE WS-AMOUNT TO WS-FIXED-DEC.
      DISPLAY 'Fixed decimal: ' WS-FIXED-DEC.

      MOVE 123.45 TO WS-LEADING-ASTER.
      DISPLAY 'Leading asterisk: ' WS-LEADING-ASTER.

      MOVE 1234.56 TO WS-CREDIT-DEBIT.
      DISPLAY 'Credit/Debit: ' WS-CREDIT-DEBIT.

      MOVE -1234.56 TO WS-NEGATIVE.
      DISPLAY 'Negative: ' WS-NEGATIVE.

      STOP RUN.

Numeric Usage Clauses

DATA DIVISION.
  WORKING-STORAGE SECTION.
  *> Different numeric storage formats
  01 WS-BINARY-NUM PIC 9(5) USAGE COMP VALUE 12345.
  01 WS-PACKED-NUM PIC 9(5) USAGE COMP-3 VALUE 12345.
  01 WS-DISPLAY-NUM PIC 9(5) USAGE DISPLAY VALUE 12345.
  01 WS-INDEX-NUM PIC 9(5) USAGE INDEX VALUE 12345.
  PROCEDURE DIVISION.
      DISPLAY 'Binary: ' WS-BINARY-NUM.
      DISPLAY 'Packed: ' WS-PACKED-NUM.
      DISPLAY 'Display: ' WS-DISPLAY-NUM.
      *> DISPLAY 'Index: ' WS-INDEX-NUM. *> Cannot display INDEX directly

      STOP RUN.

Common Pitfalls

  • Use COMP/COMP-3 for arithmetic, DISPLAY for output
  • Watch decimal alignment in computations
  • Editing characters change display but not storage
  • Signed numbers require S in PIC clause

Alphanumeric Data Types in COBOL

Alphanumeric types handle character data, including letters, numbers, and special characters. COBOL provides flexible ways to work with text data.

Basic Alphanumeric Types

IDENTIFICATION DIVISION.
  PROGRAM-ID. ALPHANUMERIC-DEMO.
  DATA DIVISION.
  WORKING-STORAGE SECTION.
  *> Basic alphanumeric fields
  01 WS-NAME PIC X(20) VALUE 'John Smith'.
  01 WS-ADDRESS PIC X(30) VALUE '123 Main Street'.
  01 WS-PHONE PIC X(10) VALUE '5551234567'.
  01 WS-ZIP-CODE PIC 9(5) VALUE 12345.
  PROCEDURE DIVISION.
      DISPLAY 'Name: ' WS-NAME.
      DISPLAY 'Address: ' WS-ADDRESS.
      DISPLAY 'Phone: ' WS-PHONE.
      DISPLAY 'ZIP Code: ' WS-ZIP-CODE.

      STOP RUN.

String Manipulation

DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-FULL-NAME PIC X(30) VALUE 'John Joseph Smith'.
  01 WS-FIRST-NAME PIC X(10).
  01 WS-LAST-NAME PIC X(10).
  01 WS-INITIALS PIC XX.
  01 WS-UPPER-NAME PIC X(30).
  01 WS-LOWER-NAME PIC X(30).
  PROCEDURE DIVISION.
      *> Extract first name
      UNSTRING WS-FULL-NAME
          DELIMITED BY SPACE
          INTO WS-FIRST-NAME
          WS-LAST-NAME
      END-UNSTRING.

      DISPLAY 'First Name: ' WS-FIRST-NAME.
      DISPLAY 'Last Name: ' WS-LAST-NAME.

      *> Create initials
      MOVE WS-FIRST-NAME(1:1) TO WS-INITIALS(1:1).
      MOVE WS-LAST-NAME(1:1) TO WS-INITIALS(2:1).
      DISPLAY 'Initials: ' WS-INITIALS.

      *> Case conversion
      MOVE FUNCTION UPPER-CASE(WS-FULL-NAME) 
          TO WS-UPPER-NAME.
      MOVE FUNCTION LOWER-CASE(WS-FULL-NAME) 
          TO WS-LOWER-NAME.

      DISPLAY 'Upper: ' WS-UPPER-NAME.
      DISPLAY 'Lower: ' WS-LOWER-NAME.

      STOP RUN.

String Functions

DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-TEXT PIC X(30) VALUE 'Hello COBOL World'.
  01 WS-SUBSTR PIC X(10).
  01 WS-POS PIC 99.
  01 WS-LENGTH PIC 99.
  01 WS-REVERSED PIC X(30).
  01 WS-TRIMMED PIC X(30).
  PROCEDURE DIVISION.
      *> Substring
      MOVE WS-TEXT(7:5) TO WS-SUBSTR. *> 'COBOL'
      DISPLAY 'Substring: ' WS-SUBSTR.

      *> String search
      MOVE FUNCTION ORD-MIN(WS-TEXT) TO WS-POS.
      DISPLAY 'First character position: ' WS-POS.

      *> String length
      COMPUTE WS-LENGTH = 
          FUNCTION LENGTH(WS-TEXT).
      DISPLAY 'Length: ' WS-LENGTH.

      *> String reversal
      MOVE FUNCTION REVERSE(WS-TEXT) 
          TO WS-REVERSED.
      DISPLAY 'Reversed: ' WS-REVERSED.

      *> Trim spaces
      MOVE FUNCTION TRIM(WS-TEXT) 
          TO WS-TRIMMED.
      DISPLAY 'Trimmed: ' WS-TRIMMED.

      STOP RUN.

Common Pitfalls

  • X fields are padded with spaces, 9 fields with zeros
  • Reference modification uses (start:length) syntax
  • UNSTRING/STRING for complex parsing/concatenation
  • Use FUNCTION for common string operations

Tables (Arrays) in COBOL

Tables in COBOL are similar to arrays in other programming languages. They allow you to store multiple values of the same data type under a single name.

Basic Table Definition

IDENTIFICATION DIVISION.
PROGRAM-ID. TABLES-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-MONTH-TABLE.
   05 WS-MONTH-NAMES PIC X(9) OCCURS 12 TIMES.

01 WS-SALES-TABLE.
   05 WS-SALES-ENTRY OCCURS 10 TIMES.
      10 WS-PRODUCT-CODE PIC 9(5).
      10 WS-PRODUCT-NAME PIC X(20).
      10 WS-SALES-AMOUNT PIC 9(5)V99.

01 WS-I PIC 99.
01 WS-J PIC 99.
PROCEDURE DIVISION.
MAIN-LOGIC.
    *> Initialize month names
    MOVE 'January'   TO WS-MONTH-NAMES(1).
    MOVE 'February'  TO WS-MONTH-NAMES(2).
    MOVE 'March'     TO WS-MONTH-NAMES(3).
    MOVE 'April'     TO WS-MONTH-NAMES(4).
    MOVE 'May'       TO WS-MONTH-NAMES(5).
    MOVE 'June'      TO WS-MONTH-NAMES(6).
    MOVE 'July'      TO WS-MONTH-NAMES(7).
    MOVE 'August'    TO WS-MONTH-NAMES(8).
    MOVE 'September' TO WS-MONTH-NAMES(9).
    MOVE 'October'   TO WS-MONTH-NAMES(10).
    MOVE 'November'  TO WS-MONTH-NAMES(11).
    MOVE 'December'  TO WS-MONTH-NAMES(12).

    *> Display all months
    PERFORM VARYING WS-I FROM 1 BY 1
        UNTIL WS-I > 12
        DISPLAY 'Month ' WS-I ': ' WS-MONTH-NAMES(WS-I)
    END-PERFORM.

    STOP RUN.

Multi-dimensional Tables

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-GRADE-TABLE.
   05 WS-STUDENT-GRADES OCCURS 5 TIMES.
      10 WS-SUBJECT-GRADE OCCURS 4 TIMES PIC 999.

01 WS-STUDENT-INDEX PIC 99.
01 WS-SUBJECT-INDEX PIC 99.
PROCEDURE DIVISION.
    *> Initialize grades table
    PERFORM VARYING WS-STUDENT-INDEX FROM 1 BY 1
        UNTIL WS-STUDENT-INDEX > 5
        PERFORM VARYING WS-SUBJECT-INDEX FROM 1 BY 1
            UNTIL WS-SUBJECT-INDEX > 4
            COMPUTE WS-SUBJECT-GRADE(WS-STUDENT-INDEX, WS-SUBJECT-INDEX)
                = (WS-STUDENT-INDEX * 10) + WS-SUBJECT-INDEX
        END-PERFORM
    END-PERFORM.

    *> Display grades
    PERFORM VARYING WS-STUDENT-INDEX FROM 1 BY 1
        UNTIL WS-STUDENT-INDEX > 5
        DISPLAY 'Student ' WS-STUDENT-INDEX ': ' 
                WS-SUBJECT-GRADE(WS-STUDENT-INDEX, 1) ' '
                WS-SUBJECT-GRADE(WS-STUDENT-INDEX, 2) ' '
                WS-SUBJECT-GRADE(WS-STUDENT-INDEX, 3) ' '
                WS-SUBJECT-GRADE(WS-STUDENT-INDEX, 4)
    END-PERFORM.

    STOP RUN.

Common Pitfalls

  • Always check bounds to avoid subscript out of range
  • Use PERFORM VARYING for efficient table processing
  • Initialize table elements before use
  • Multi-dimensional tables use comma-separated subscripts

Table Indexing in COBOL

COBOL provides both indexing and subscripting for table access. Indexes are more efficient for large tables and support special operations.

Using INDEX vs SUBSCRIPT

IDENTIFICATION DIVISION.
PROGRAM-ID. INDEXING-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-EMPLOYEE-TABLE.
   05 WS-EMPLOYEE OCCURS 100 TIMES
      INDEXED BY EMP-INDEX.
      10 WS-EMP-ID PIC 9(5).
      10 WS-EMP-NAME PIC X(20).
      10 WS-EMP-SALARY PIC 9(6)V99.

01 WS-SUBSCRIPT PIC 999.
01 WS-FOUND-INDEX PIC 999.
PROCEDURE DIVISION.
MAIN-LOGIC.
    *> Initialize some employee data
    MOVE 10001 TO WS-EMP-ID(1).
    MOVE 'John Smith' TO WS-EMP-NAME(1).
    MOVE 50000.00 TO WS-EMP-SALARY(1).

    MOVE 10002 TO WS-EMP-ID(2).
    MOVE 'Jane Doe' TO WS-EMP-NAME(2).
    MOVE 55000.00 TO WS-EMP-SALARY(2).

    *> Using subscript
    MOVE 1 TO WS-SUBSCRIPT.
    DISPLAY 'Employee 1: ' WS-EMP-NAME(WS-SUBSCRIPT).

    *> Using index
    SET EMP-INDEX TO 1.
    DISPLAY 'Employee 1: ' WS-EMP-NAME(EMP-INDEX).

    STOP RUN.

Index Operations

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NUMBERS-TABLE.
   05 WS-NUMBER PIC 999 OCCURS 50 TIMES
      INDEXED BY NUM-INDEX.

01 WS-SEARCH-VALUE PIC 999 VALUE 42.
01 WS-FOUND PIC X VALUE 'N'.
   88 FOUND-YES VALUE 'Y'.
   88 FOUND-NO VALUE 'N'.
PROCEDURE DIVISION.
    *> Initialize table with values
    PERFORM VARYING NUM-INDEX FROM 1 BY 1
        UNTIL NUM-INDEX > 50
        COMPUTE WS-NUMBER(NUM-INDEX) = NUM-INDEX * 2
    END-PERFORM.

    *> Search using index
    SET NUM-INDEX TO 1.
    PERFORM UNTIL NUM-INDEX > 50 OR FOUND-YES
        IF WS-NUMBER(NUM-INDEX) = WS-SEARCH-VALUE
            SET FOUND-YES TO TRUE
            DISPLAY 'Found at position: ' NUM-INDEX
        ELSE
            SET NUM-INDEX UP BY 1
        END-IF
    END-PERFORM.

    IF FOUND-NO
        DISPLAY 'Value not found'
    END-IF.

    STOP RUN.

SEARCH with INDEX

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-PRODUCT-TABLE.
   05 WS-PRODUCT OCCURS 20 TIMES
      ASCENDING KEY IS WS-PROD-CODE
      INDEXED BY PROD-INDEX.
      10 WS-PROD-CODE PIC 9(5).
      10 WS-PROD-NAME PIC X(20).
      10 WS-PROD-PRICE PIC 9(4)V99.

01 WS-TARGET-CODE PIC 9(5) VALUE 12345.
PROCEDURE DIVISION.
    *> Initialize sorted product table
    MOVE 11111 TO WS-PROD-CODE(1).
    MOVE 'Laptop' TO WS-PROD-NAME(1).
    MOVE 999.99 TO WS-PROD-PRICE(1).

    MOVE 12345 TO WS-PROD-CODE(2).
    MOVE 'Mouse' TO WS-PROD-NAME(2).
    MOVE 25.50 TO WS-PROD-PRICE(2).

    MOVE 13579 TO WS-PROD-CODE(3).
    MOVE 'Keyboard' TO WS-PROD-NAME(3).
    MOVE 45.00 TO WS-PROD-PRICE(3).

    *> Binary search using SEARCH ALL
    SEARCH ALL WS-PRODUCT
        AT END DISPLAY 'Product not found'
        WHEN WS-PROD-CODE(PROD-INDEX) = WS-TARGET-CODE
            DISPLAY 'Found: ' WS-PROD-NAME(PROD-INDEX)
                    ' Price: ' WS-PROD-PRICE(PROD-INDEX)
    END-SEARCH.

    STOP RUN.

Common Pitfalls

  • Indexes are more efficient but require SET statements
  • SEARCH ALL requires sorted data with ASCENDING/DESCENDING KEY
  • Always check index bounds to avoid out-of-range errors
  • Use SET to manipulate indexes, not MOVE

Variables in COBOL

Variables in COBOL are defined in the DATA DIVISION and have specific characteristics like level numbers, picture clauses, and usage clauses.

Variable Declaration

IDENTIFICATION DIVISION.
PROGRAM-ID. VARIABLES-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
*> Elementary items
01 WS-STUDENT-NAME PIC X(30).
01 WS-STUDENT-AGE PIC 99.
01 WS-STUDENT-GPA PIC 9V99.
01 WS-ENROLLED PIC X.
   88 IS-ENROLLED VALUE 'Y'.
   88 NOT-ENROLLED VALUE 'N'.

*> Group items
01 WS-STUDENT-RECORD.
   05 WS-FIRST-NAME PIC X(15).
   05 WS-LAST-NAME PIC X(15).
   05 WS-ADDRESS.
      10 WS-STREET PIC X(25).
      10 WS-CITY PIC X(15).
      10 WS-STATE PIC XX.
      10 WS-ZIP PIC 9(5).

*> Constants
01 WS-CONSTANTS.
   05 WS-MAX-STUDENTS PIC 999 VALUE 100.
   05 WS-MIN-AGE PIC 99 VALUE 16.
   05 WS-SCHOOL-NAME PIC X(20) VALUE 'CENTRAL HIGH SCHOOL'.
PROCEDURE DIVISION.
MAIN-LOGIC.
    MOVE 'John' TO WS-FIRST-NAME.
    MOVE 'Smith' TO WS-LAST-NAME.
    MOVE 18 TO WS-STUDENT-AGE.
    MOVE 3.75 TO WS-STUDENT-GPA.
    MOVE 'Y' TO WS-ENROLLED.

    DISPLAY 'Student: ' WS-FIRST-NAME ' ' WS-LAST-NAME.
    DISPLAY 'Age: ' WS-STUDENT-AGE ' GPA: ' WS-STUDENT-GPA.
    
    IF IS-ENROLLED
        DISPLAY 'Student is enrolled'
    END-IF.

    STOP RUN.

VALUE Clause and Initialization

DATA DIVISION.
WORKING-STORAGE SECTION.
*> Different ways to initialize variables
01 WS-INITIALIZED-VARS.
   05 WS-COUNT PIC 999 VALUE ZERO.
   05 WS-TOTAL PIC 9(5)V99 VALUE 0.00.
   05 WS-FLAG PIC X VALUE 'N'.
   05 WS-MESSAGE PIC X(20) VALUE 'HELLO WORLD'.
   05 WS-ARRAY OCCURS 5 TIMES PIC 999 VALUE 100.

01 WS-DEFAULT-VALUES.
   05 WS-NUMERIC-DEFAULT PIC 999.
   05 WS-ALPHANUMERIC-DEFAULT PIC X(10).
   05 WS-GROUP-DEFAULT.
      10 WS-PART1 PIC XX.
      10 WS-PART2 PIC 999.
PROCEDURE DIVISION.
    *> Display default values
    DISPLAY 'Numeric default: [' WS-NUMERIC-DEFAULT ']'.
    DISPLAY 'Alphanumeric default: [' WS-ALPHANUMERIC-DEFAULT ']'.

    *> Initialize with INITIALIZE
    INITIALIZE WS-DEFAULT-VALUES.
    DISPLAY 'After INITIALIZE:'.
    DISPLAY 'Numeric: [' WS-NUMERIC-DEFAULT ']'.
    DISPLAY 'Alphanumeric: [' WS-ALPHANUMERIC-DEFAULT ']'.

    *> Initialize with specific values
    INITIALIZE WS-DEFAULT-VALUES
        REPLACING NUMERIC BY 123
                  ALPHANUMERIC BY 'ABC'.

    DISPLAY 'After REPLACING:'.
    DISPLAY 'Numeric: [' WS-NUMERIC-DEFAULT ']'.
    DISPLAY 'Alphanumeric: [' WS-ALPHANUMERIC-DEFAULT ']'.

    STOP RUN.

Working with 88-level Conditions

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-GRADE PIC X.
   88 A-GRADE VALUE 'A'.
   88 B-GRADE VALUE 'B'.
   88 C-GRADE VALUE 'C'.
   88 D-GRADE VALUE 'D'.
   88 F-GRADE VALUE 'F'.
   88 VALID-GRADE VALUE 'A' 'B' 'C' 'D' 'F'.

01 WS-STATUS PIC X.
   88 ACTIVE-STATUS VALUE 'A'.
   88 INACTIVE-STATUS VALUE 'I'.
   88 PENDING-STATUS VALUE 'P'.

01 WS-SCORE PIC 999.
PROCEDURE DIVISION.
    MOVE 85 TO WS-SCORE.
    
    *> Determine grade based on score
    EVALUATE TRUE
        WHEN WS-SCORE >= 90 MOVE 'A' TO WS-GRADE
        WHEN WS-SCORE >= 80 MOVE 'B' TO WS-GRADE
        WHEN WS-SCORE >= 70 MOVE 'C' TO WS-GRADE
        WHEN WS-SCORE >= 60 MOVE 'D' TO WS-GRADE
        WHEN OTHER MOVE 'F' TO WS-GRADE
    END-EVALUATE.

    *> Use 88-level for readable conditions
    EVALUATE TRUE
        WHEN A-GRADE DISPLAY 'Excellent!'
        WHEN B-GRADE DISPLAY 'Good job!'
        WHEN C-GRADE DISPLAY 'Satisfactory'
        WHEN D-GRADE DISPLAY 'Needs improvement'
        WHEN F-GRADE DISPLAY 'Failed'
    END-EVALUATE.

    STOP RUN.

Common Pitfalls

  • PIC X fields default to spaces, PIC 9 fields to zeros
  • Use 88-level for meaningful condition names
  • INITIALIZE affects entire group items
  • VALUE clause only works in WORKING-STORAGE, not in FILE SECTION

IF, ELSE and Nested IF Statements

COBOL provides comprehensive conditional processing with IF statements, supporting simple conditions, ELSE clauses, and nested IF structures.

Basic IF-ELSE Structure

IDENTIFICATION DIVISION.
PROGRAM-ID. IF-ELSE-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-AGE PIC 99.
01 WS-INCOME PIC 9(6).
01 WS-CREDIT-SCORE PIC 999.
01 WS-ELIGIBLE PIC X.
   88 IS-ELIGIBLE VALUE 'Y'.
   88 NOT-ELIGIBLE VALUE 'N'.
PROCEDURE DIVISION.
MAIN-LOGIC.
    MOVE 25 TO WS-AGE.
    MOVE 45000 TO WS-INCOME.
    MOVE 720 TO WS-CREDIT-SCORE.

    *> Simple IF statement
    IF WS-AGE >= 18
        DISPLAY 'Adult customer'
    END-IF.

    *> IF-ELSE statement
    IF WS-INCOME > 50000
        DISPLAY 'High income customer'
    ELSE
        DISPLAY 'Medium income customer'
    END-IF.

    *> Multiple conditions
    IF WS-AGE >= 21 AND WS-CREDIT-SCORE > 700
        MOVE 'Y' TO WS-ELIGIBLE
        DISPLAY 'Loan approved'
    ELSE
        MOVE 'N' TO WS-ELIGIBLE
        DISPLAY 'Loan denied'
    END-IF.

    STOP RUN.

Nested IF Statements

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-TEMPERATURE PIC S999.
01 WS-HUMIDITY PIC 999.
01 WS-WEATHER-CONDITION PIC X(10).
PROCEDURE DIVISION.
    MOVE 85 TO WS-TEMPERATURE.
    MOVE 65 TO WS-HUMIDITY.

    *> Nested IF for complex decision making
    IF WS-TEMPERATURE > 90
        IF WS-HUMIDITY > 70
            MOVE 'HOT-HUMID' TO WS-WEATHER-CONDITION
        ELSE
            MOVE 'HOT-DRY' TO WS-WEATHER-CONDITION
        END-IF
    ELSE
        IF WS-TEMPERATURE > 70
            IF WS-HUMIDITY > 70
                MOVE 'WARM-HUMID' TO WS-WEATHER-CONDITION
            ELSE
                MOVE 'WARM-DRY' TO WS-WEATHER-CONDITION
            END-IF
        ELSE
            MOVE 'COOL' TO WS-WEATHER-CONDITION
        END-IF
    END-IF.

    DISPLAY 'Weather: ' WS-WEATHER-CONDITION.

    STOP RUN.

ELSE IF and Complex Conditions

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-GRADE PIC X.
01 WS-SCORE PIC 999.
01 WS-MESSAGE PIC X(30).
PROCEDURE DIVISION.
    MOVE 87 TO WS-SCORE.

    *> ELSE IF equivalent in COBOL
    IF WS-SCORE >= 90
        MOVE 'A' TO WS-GRADE
        MOVE 'Excellent work!' TO WS-MESSAGE
    ELSE
    IF WS-SCORE >= 80
        MOVE 'B' TO WS-GRADE
        MOVE 'Good job!' TO WS-MESSAGE
    ELSE
    IF WS-SCORE >= 70
        MOVE 'C' TO WS-GRADE
        MOVE 'Satisfactory' TO WS-MESSAGE
    ELSE
    IF WS-SCORE >= 60
        MOVE 'D' TO WS-GRADE
        MOVE 'Needs improvement' TO WS-MESSAGE
    ELSE
        MOVE 'F' TO WS-GRADE
        MOVE 'Failed - try again' TO WS-MESSAGE
    END-IF END-IF END-IF END-IF.

    DISPLAY 'Grade: ' WS-GRADE ' - ' WS-MESSAGE.

    *> Alternative using EVALUATE (often cleaner)
    EVALUATE TRUE
        WHEN WS-SCORE >= 90
            MOVE 'A' TO WS-GRADE
        WHEN WS-SCORE >= 80
            MOVE 'B' TO WS-GRADE
        WHEN WS-SCORE >= 70
            MOVE 'C' TO WS-GRADE
        WHEN WS-SCORE >= 60
            MOVE 'D' TO WS-GRADE
        WHEN OTHER
            MOVE 'F' TO WS-GRADE
    END-EVALUATE.

    DISPLAY 'Grade (EVALUATE): ' WS-GRADE.

    STOP RUN.

Common Pitfalls

  • Always use END-IF to terminate IF statements
  • Nested IF requires proper indentation for readability
  • Consider EVALUATE for multiple mutually exclusive conditions
  • Use parentheses to clarify complex condition precedence

PERFORM Loop in COBOL

The PERFORM statement is COBOL's primary looping mechanism. It can execute paragraphs or sections multiple times with various control structures.

Basic PERFORM Loops

IDENTIFICATION DIVISION.
PROGRAM-ID. PERFORM-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-COUNTER PIC 99.
01 WS-TOTAL PIC 999.
01 WS-NUMBER PIC 999.
PROCEDURE DIVISION.
MAIN-LOGIC.
    *> PERFORM a paragraph once
    PERFORM INITIALIZE-VARS.
    
    *> PERFORM a paragraph multiple times
    PERFORM PROCESS-DATA 5 TIMES.
    
    *> PERFORM UNTIL loop
    MOVE 0 TO WS-TOTAL.
    PERFORM ACCUMULATE-TOTAL 
        UNTIL WS-COUNTER > 10.
    
    DISPLAY 'Final total: ' WS-TOTAL.
    STOP RUN.

INITIALIZE-VARS.
    MOVE 0 TO WS-COUNTER.
    MOVE 0 TO WS-TOTAL.
    DISPLAY 'Variables initialized.'.

PROCESS-DATA.
    ADD 1 TO WS-COUNTER.
    COMPUTE WS-NUMBER = WS-COUNTER * 10.
    DISPLAY 'Counter: ' WS-COUNTER ' Number: ' WS-NUMBER.

ACCUMULATE-TOTAL.
    ADD 1 TO WS-COUNTER.
    COMPUTE WS-TOTAL = WS-TOTAL + WS-COUNTER.
    DISPLAY 'Counter: ' WS-COUNTER ' Total: ' WS-TOTAL.

PERFORM WITH TEST

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-INDEX PIC 99.
01 WS-SUM PIC 999.
PROCEDURE DIVISION.
    *> PERFORM UNTIL with TEST BEFORE (default)
    DISPLAY 'TEST BEFORE (default):'.
    MOVE 1 TO WS-INDEX.
    MOVE 0 TO WS-SUM.
    PERFORM WITH TEST BEFORE
        UNTIL WS-INDEX > 5
        COMPUTE WS-SUM = WS-SUM + WS-INDEX
        DISPLAY 'Index: ' WS-INDEX ' Sum: ' WS-SUM
        ADD 1 TO WS-INDEX
    END-PERFORM.

    DISPLAY 'Final sum (TEST BEFORE): ' WS-SUM.

    *> PERFORM UNTIL with TEST AFTER
    DISPLAY 'TEST AFTER:'.
    MOVE 1 TO WS-INDEX.
    MOVE 0 TO WS-SUM.
    PERFORM WITH TEST AFTER
        UNTIL WS-INDEX > 5
        COMPUTE WS-SUM = WS-SUM + WS-INDEX
        DISPLAY 'Index: ' WS-INDEX ' Sum: ' WS-SUM
        ADD 1 TO WS-INDEX
    END-PERFORM.

    DISPLAY 'Final sum (TEST AFTER): ' WS-SUM.

    STOP RUN.

Inline PERFORM

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-I PIC 99.
01 WS-J PIC 99.
01 WS-PRODUCT PIC 999.
PROCEDURE DIVISION.
    *> Inline PERFORM - no external paragraph needed
    DISPLAY 'Multiplication Table (1-5):'.
    
    PERFORM VARYING WS-I FROM 1 BY 1
        UNTIL WS-I > 5
        PERFORM VARYING WS-J FROM 1 BY 1
            UNTIL WS-J > 5
            COMPUTE WS-PRODUCT = WS-I * WS-J
            DISPLAY WS-I ' x ' WS-J ' = ' WS-PRODUCT
        END-PERFORM
        DISPLAY '---'
    END-PERFORM.

    *> PERFORM with multiple varying items
    DISPLAY 'Multiple counters:'.
    PERFORM VARYING WS-I FROM 1 BY 1
              VARYING WS-J FROM 10 BY -1
        UNTIL WS-I > 5
        DISPLAY 'I: ' WS-I ' J: ' WS-J
    END-PERFORM.

    STOP RUN.

Common Pitfalls

  • TEST BEFORE checks condition before execution (0 or more times)
  • TEST AFTER checks condition after execution (1 or more times)
  • Use inline PERFORM for simple loops to avoid paragraph calls
  • Ensure loop variables are properly initialized

PERFORM VARYING Loop

PERFORM VARYING provides powerful looping capabilities with automatic counter management, similar to for loops in other languages.

Basic PERFORM VARYING

IDENTIFICATION DIVISION.
PROGRAM-ID. PERFORM-VARYING-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-INDEX PIC 99.
01 WS-NUMBER PIC 999.
01 WS-SQUARE PIC 9999.
01 WS-CUBE PIC 99999.
PROCEDURE DIVISION.
MAIN-LOGIC.
    *> Simple VARYING loop
    DISPLAY 'Numbers 1 to 10:'.
    PERFORM VARYING WS-INDEX FROM 1 BY 1
        UNTIL WS-INDEX > 10
        DISPLAY 'Number: ' WS-INDEX
    END-PERFORM.

    *> VARYING with calculations
    DISPLAY 'Squares and Cubes:'.
    PERFORM VARYING WS-INDEX FROM 1 BY 1
        UNTIL WS-INDEX > 5
        COMPUTE WS-NUMBER = WS-INDEX
        COMPUTE WS-SQUARE = WS-INDEX ** 2
        COMPUTE WS-CUBE = WS-INDEX ** 3
        DISPLAY WS-INDEX ': ' WS-SQUARE ' ' WS-CUBE
    END-PERFORM.

    STOP RUN.

Multiple VARYING Clauses

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-ROW PIC 99.
01 WS-COL PIC 99.
01 WS-VALUE PIC 999.
01 WS-MATRIX-SUM PIC 9999.
PROCEDURE DIVISION.
    *> Nested loops using multiple VARYING
    DISPLAY '2D Matrix:'.
    MOVE 0 TO WS-MATRIX-SUM.
    
    PERFORM VARYING WS-ROW FROM 1 BY 1
            UNTIL WS-ROW > 3
        PERFORM VARYING WS-COL FROM 1 BY 1
                UNTIL WS-COL > 4
            COMPUTE WS-VALUE = (WS-ROW * 10) + WS-COL
            DISPLAY 'Matrix[' WS-ROW ',' WS-COL '] = ' WS-VALUE
            COMPUTE WS-MATRIX-SUM = WS-MATRIX-SUM + WS-VALUE
        END-PERFORM
    END-PERFORM.
    
    DISPLAY 'Matrix sum: ' WS-MATRIX-SUM.

    *> Single PERFORM with multiple counters
    DISPLAY 'Coordinate pairs:'.
    PERFORM VARYING WS-ROW FROM 1 BY 1
              VARYING WS-COL FROM 5 BY -1
        UNTIL WS-ROW > 5
        DISPLAY '(' WS-ROW ',' WS-COL ')'
    END-PERFORM.

    STOP RUN.

Complex VARYING Patterns

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-START PIC S99.
01 WS-END PIC S99.
01 WS-STEP PIC S99.
01 WS-COUNTER PIC S99.
01 WS-SUM PIC S999.
PROCEDURE DIVISION.
    *> Different step values
    DISPLAY 'Even numbers 2 to 10:'.
    PERFORM VARYING WS-COUNTER FROM 2 BY 2
        UNTIL WS-COUNTER > 10
        DISPLAY 'Even: ' WS-COUNTER
    END-PERFORM.

    *> Negative step (countdown)
    DISPLAY 'Countdown from 10 to 1:'.
    PERFORM VARYING WS-COUNTER FROM 10 BY -1
        UNTIL WS-COUNTER < 1
        DISPLAY WS-COUNTER
    END-PERFORM.

    *> Using variables for control
    MOVE 5 TO WS-START.
    MOVE 25 TO WS-END.
    MOVE 5 TO WS-STEP.
    MOVE 0 TO WS-SUM.
    
    DISPLAY 'Summing from ' WS-START ' to ' WS-END 
            ' by ' WS-STEP.
    PERFORM VARYING WS-COUNTER FROM WS-START BY WS-STEP
        UNTIL WS-COUNTER > WS-END
        COMPUTE WS-SUM = WS-SUM + WS-COUNTER
        DISPLAY 'Added ' WS-COUNTER ', sum = ' WS-SUM
    END-PERFORM.
    
    DISPLAY 'Final sum: ' WS-SUM.

    STOP RUN.

Common Pitfalls

  • Ensure step value doesn't cause infinite loops
  • Use signed fields for negative steps or decreasing counters
  • Multiple VARYING clauses execute in parallel, not nested
  • Test boundary conditions carefully

Loop Control in COBOL

COBOL provides several mechanisms for controlling loop execution, including EXIT PERFORM, GO TO, and conditional termination.

EXIT PERFORM and GO TO

IDENTIFICATION DIVISION.
PROGRAM-ID. LOOP-CONTROL-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-INDEX PIC 99.
01 WS-NUMBER PIC 999.
01 WS-FOUND PIC X VALUE 'N'.
   88 NUMBER-FOUND VALUE 'Y'.
   88 NUMBER-NOT-FOUND VALUE 'N'.
PROCEDURE DIVISION.
MAIN-LOGIC.
    *> EXIT PERFORM for early termination
    DISPLAY 'Searching for number 7:'.
    MOVE 'N' TO WS-FOUND.
    PERFORM VARYING WS-INDEX FROM 1 BY 1
        UNTIL WS-INDEX > 10
        COMPUTE WS-NUMBER = WS-INDEX * 2
        DISPLAY 'Checking: ' WS-NUMBER
        
        IF WS-NUMBER = 7
            MOVE 'Y' TO WS-FOUND
            DISPLAY 'Found 7 at iteration ' WS-INDEX
            EXIT PERFORM
        END-IF
    END-PERFORM.
    
    IF NUMBER-NOT-FOUND
        DISPLAY 'Number 7 not found'
    END-IF.

    *> GO TO for complex control flow
    DISPLAY 'Using GO TO for loop control:'.
    MOVE 1 TO WS-INDEX.
    
    PROCESS-LOOP.
        IF WS-INDEX > 5
            GO TO END-OF-LOOP
        END-IF.
        
        DISPLAY 'Processing item ' WS-INDEX.
        ADD 1 TO WS-INDEX.
        GO TO PROCESS-LOOP.
    
    END-OF-LOOP.
    DISPLAY 'Loop completed.'.

    STOP RUN.

Conditional Loop Control

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-COUNTER PIC 99.
01 WS-TOTAL PIC 999.
01 WS-INPUT-VALUE PIC 999.
01 WS-VALID-INPUT PIC X.
   88 VALID-VALUE VALUE 'Y'.
   88 INVALID-VALUE VALUE 'N'.
PROCEDURE DIVISION.
    *> Continue and break patterns
    DISPLAY 'Processing numbers (skip 5, break at 8):'.
    MOVE 0 TO WS-TOTAL.
    
    PERFORM VARYING WS-COUNTER FROM 1 BY 1
        UNTIL WS-COUNTER > 10
        
        *> Skip specific value (like 'continue')
        IF WS-COUNTER = 5
            DISPLAY 'Skipping 5'
            EXIT PERFORM CYCLE
        END-IF
        
        *> Break loop condition
        IF WS-COUNTER = 8
            DISPLAY 'Breaking at 8'
            EXIT PERFORM
        END-IF
        
        COMPUTE WS-TOTAL = WS-TOTAL + WS-COUNTER
        DISPLAY 'Added ' WS-COUNTER ', total: ' WS-TOTAL
    END-PERFORM.
    
    DISPLAY 'Final total: ' WS-TOTAL.

    *> Input validation loop
    DISPLAY 'Input validation demo:'.
    MOVE 'N' TO WS-VALID-INPUT.
    
    PERFORM UNTIL VALID-VALUE
        DISPLAY 'Enter a number between 1 and 100:'
        ACCEPT WS-INPUT-VALUE
        
        IF WS-INPUT-VALUE >= 1 AND WS-INPUT-VALUE <= 100
            MOVE 'Y' TO WS-VALID-INPUT
            DISPLAY 'Valid input: ' WS-INPUT-VALUE
        ELSE
            DISPLAY 'Invalid input. Try again.'
        END-IF
    END-PERFORM.

    STOP RUN.

Nested Loop Control

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-I PIC 99.
01 WS-J PIC 99.
01 WS-K PIC 99.
01 WS-SEARCH-VALUE PIC 999 VALUE 25.
01 WS-FOUND PIC X VALUE 'N'.
PROCEDURE DIVISION.
    *> Breaking out of nested loops
    DISPLAY 'Searching in 3D array:'.
    MOVE 'N' TO WS-FOUND.
    
    PERFORM VARYING WS-I FROM 1 BY 1
        UNTIL WS-I > 3 OR FOUND
        
        PERFORM VARYING WS-J FROM 1 BY 1
            UNTIL WS-J > 3 OR FOUND
            
            PERFORM VARYING WS-K FROM 1 BY 1
                UNTIL WS-K > 3 OR FOUND
                
                COMPUTE WS-SEARCH-VALUE = 
                    (WS-I * 100) + (WS-J * 10) + WS-K
                
                DISPLAY 'Checking [' WS-I ',' WS-J ',' WS-K '] = ' 
                        WS-SEARCH-VALUE
                
                *> Break all loops when condition met
                IF WS-SEARCH-VALUE = 123
                    MOVE 'Y' TO WS-FOUND
                    DISPLAY 'Found target at [' 
                            WS-I ',' WS-J ',' WS-K ']'
                    EXIT PERFORM
                END-IF
            END-PERFORM
        END-PERFORM
    END-PERFORM.
    
    IF NOT FOUND
        DISPLAY 'Target not found'
    END-IF.

    STOP RUN.

Common Pitfalls

  • EXIT PERFORM terminates the innermost PERFORM
  • EXIT PERFORM CYCLE skips to next iteration
  • GO TO can make code hard to read - use sparingly
  • Ensure all loops have proper termination conditions

Nested Loops in COBOL

Nested loops allow you to process multi-dimensional data structures and complex iterative patterns by placing loops within other loops.

Basic Nested Loops

IDENTIFICATION DIVISION.
PROGRAM-ID. NESTED-LOOPS-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-OUTER PIC 99.
01 WS-INNER PIC 99.
01 WS-PRODUCT PIC 999.
PROCEDURE DIVISION.
MAIN-LOGIC.
    *> Simple nested loops for multiplication table
    DISPLAY 'Multiplication Table (1-3):'.
    DISPLAY '   1  2  3'.
    DISPLAY '  --------'.
    
    PERFORM VARYING WS-OUTER FROM 1 BY 1
        UNTIL WS-OUTER > 3
        DISPLAY WS-OUTER '|' WITH NO ADVANCING
        
        PERFORM VARYING WS-INNER FROM 1 BY 1
            UNTIL WS-INNER > 3
            COMPUTE WS-PRODUCT = WS-OUTER * WS-INNER
            DISPLAY WS-PRODUCT ' ' WITH NO ADVANCING
        END-PERFORM
        
        DISPLAY '' *> New line
    END-PERFORM.

    STOP RUN.

Pattern Generation with Nested Loops

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-ROW PIC 99.
01 WS-COL PIC 99.
01 WS-STARS PIC X(20).
PROCEDURE DIVISION.
    *> Pyramid pattern
    DISPLAY 'Pyramid Pattern:'.
    PERFORM VARYING WS-ROW FROM 1 BY 1
        UNTIL WS-ROW > 5
        MOVE SPACES TO WS-STARS
        MOVE ALL '*' TO WS-STARS(1:WS-ROW)
        DISPLAY WS-STARS
    END-PERFORM.

    *> Box pattern with nested loops
    DISPLAY 'Box Pattern:'.
    PERFORM VARYING WS-ROW FROM 1 BY 1
        UNTIL WS-ROW > 6
        PERFORM VARYING WS-COL FROM 1 BY 1
            UNTIL WS-COL > 10
            IF WS-ROW = 1 OR WS-ROW = 6 OR
               WS-COL = 1 OR WS-COL = 10
                DISPLAY '*' WITH NO ADVANCING
            ELSE
                DISPLAY ' ' WITH NO ADVANCING
            END-IF
        END-PERFORM
        DISPLAY '' *> New line
    END-PERFORM.

    STOP RUN.

Complex Data Processing

DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-STUDENT-INDEX PIC 99.
01 WS-SUBJECT-INDEX PIC 99.
01 WS-EXAM-INDEX PIC 99.
01 WS-STUDENT-COUNT PIC 99 VALUE 3.
01 WS-SUBJECT-COUNT PIC 99 VALUE 4.
01 WS-EXAM-COUNT PIC 99 VALUE 2.

01 WS-GRADE-TABLE.
   05 WS-STUDENT OCCURS 3 TIMES.
      10 WS-STUDENT-NAME PIC X(15).
      10 WS-SUBJECT OCCURS 4 TIMES.
         15 WS-EXAM OCCURS 2 TIMES PIC 999.

01 WS-TOTAL-SCORE PIC 9(5).
01 WS-AVERAGE PIC 999.
PROCEDURE DIVISION.
    *> Initialize student data
    MOVE 'Alice' TO WS-STUDENT-NAME(1).
    MOVE 'Bob' TO WS-STUDENT-NAME(2).
    MOVE 'Carol' TO WS-STUDENT-NAME(3).
    
    *> Initialize grades
    PERFORM VARYING WS-STUDENT-INDEX FROM 1 BY 1
        UNTIL WS-STUDENT-INDEX > WS-STUDENT-COUNT
        PERFORM VARYING WS-SUBJECT-INDEX FROM 1 BY 1
            UNTIL WS-SUBJECT-INDEX > WS-SUBJECT-COUNT
            PERFORM VARYING WS-EXAM-INDEX FROM 1 BY 1
                UNTIL WS-EXAM-INDEX > WS-EXAM-COUNT
                COMPUTE WS-EXAM(WS-STUDENT-INDEX, 
                               WS-SUBJECT-INDEX, 
                               WS-EXAM-INDEX)
                    = (WS-STUDENT-INDEX * 20) + 
                      (WS-SUBJECT-INDEX * 5) + 
                      (WS-EXAM-INDEX * 3)
            END-PERFORM
        END-PERFORM
    END-PERFORM.

    *> Calculate and display averages
    DISPLAY 'Student Averages:'.
    PERFORM VARYING WS-STUDENT-INDEX FROM 1 BY 1
        UNTIL WS-STUDENT-INDEX > WS-STUDENT-COUNT
        MOVE 0 TO WS-TOTAL-SCORE
        MOVE 0 TO WS-AVERAGE
        
        PERFORM VARYING WS-SUBJECT-INDEX FROM 1 BY 1
            UNTIL WS-SUBJECT-INDEX > WS-SUBJECT-COUNT
            PERFORM VARYING WS-EXAM-INDEX FROM 1 BY 1
                UNTIL WS-EXAM-INDEX > WS-EXAM-COUNT
                COMPUTE WS-TOTAL-SCORE = WS-TOTAL-SCORE +
                    WS-EXAM(WS-STUDENT-INDEX, 
                           WS-SUBJECT-INDEX, 
                           WS-EXAM-INDEX)
            END-PERFORM
        END-PERFORM
        
        COMPUTE WS-AVERAGE = WS-TOTAL-SCORE / 
                            (WS-SUBJECT-COUNT * WS-EXAM-COUNT)
        DISPLAY WS-STUDENT-NAME(WS-STUDENT-INDEX) 
                ': ' WS-AVERAGE
    END-PERFORM.

    STOP RUN.

Common Pitfalls

  • Nested loops can significantly impact performance
  • Ensure proper initialization of all loop counters
  • Use meaningful names for nested loop variables
  • Watch for off-by-one errors in boundary conditions

Paragraphs and Sections in COBOL

Paragraphs and sections are the primary organizational units in COBOL's PROCEDURE DIVISION, providing modularity and structure to program logic.

Paragraphs and Basic Structure

IDENTIFICATION DIVISION.
PROGRAM-ID. PARAGRAPHS-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-EMPLOYEE-COUNT PIC 999.
01 WS-TOTAL-SALARY PIC 9(6)V99.
01 WS-AVERAGE-SALARY PIC 9(5)V99.
PROCEDURE DIVISION.
MAIN-PROGRAM.
    DISPLAY 'Program started.'.
    PERFORM INITIALIZE-DATA.
    PERFORM PROCESS-EMPLOYEES.
    PERFORM CALCULATE-STATISTICS.
    PERFORM DISPLAY-RESULTS.
    STOP RUN.

INITIALIZE-DATA.
    MOVE 0 TO WS-EMPLOYEE-COUNT.
    MOVE 0 TO WS-TOTAL-SALARY.
    MOVE 0 TO WS-AVERAGE-SALARY.
    DISPLAY 'Data initialized.'.

PROCESS-EMPLOYEES.
    DISPLAY 'Processing employees...'.
    *> Simulate processing some employees
    ADD 5 TO WS-EMPLOYEE-COUNT.
    COMPUTE WS-TOTAL-SALARY = 250000.00.
    DISPLAY 'Processed ' WS-EMPLOYEE-COUNT ' employees.'.

CALCULATE-STATISTICS.
    DISPLAY 'Calculating statistics...'.
    IF WS-EMPLOYEE-COUNT > 0
        COMPUTE WS-AVERAGE-SALARY = 
            WS-TOTAL-SALARY / WS-EMPLOYEE-COUNT
    ELSE
        MOVE 0 TO WS-AVERAGE-SALARY
    END-IF.

DISPLAY-RESULTS.
    DISPLAY '=== RESULTS ==='.
    DISPLAY 'Employee count: ' WS-EMPLOYEE-COUNT.
    DISPLAY 'Total salary: ' WS-TOTAL-SALARY.
    DISPLAY 'Average salary: ' WS-AVERAGE-SALARY.
    DISPLAY 'Program completed successfully.'.

Sections and Paragraph Organization

IDENTIFICATION DIVISION.
PROGRAM-ID. SECTIONS-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CUSTOMER-DATA.
   05 WS-CUST-NAME PIC X(20).
   05 WS-CUST-BALANCE PIC 9(5)V99.
   05 WS-CUST-CREDIT-LIMIT PIC 9(5)V99.
PROCEDURE DIVISION.
MAIN-CONTROL-SECTION.
    DISPLAY 'Customer Management System'.
    PERFORM INPUT-SECTION.
    PERFORM PROCESSING-SECTION.
    PERFORM OUTPUT-SECTION.
    STOP RUN.

INPUT-SECTION.
INPUT-CUSTOMER-DATA.
    DISPLAY 'Enter customer name:'.
    ACCEPT WS-CUST-NAME.
    DISPLAY 'Enter customer balance:'.
    ACCEPT WS-CUST-BALANCE.
    DISPLAY 'Enter credit limit:'.
    ACCEPT WS-CUST-CREDIT-LIMIT.
    DISPLAY 'Input completed.'.

VALIDATE-INPUT-DATA.
    IF WS-CUST-NAME = SPACES
        DISPLAY 'Error: Customer name required'
        PERFORM INPUT-CUSTOMER-DATA
    END-IF.

PROCESSING-SECTION.
CALCULATE-CREDIT.
    IF WS-CUST-BALANCE > WS-CUST-CREDIT-LIMIT
        DISPLAY 'Credit limit exceeded!'
    ELSE
        COMPUTE WS-CUST-CREDIT-LIMIT = 
            WS-CUST-CREDIT-LIMIT - WS-CUST-BALANCE
        DISPLAY 'Credit available: ' WS-CUST-CREDIT-LIMIT
    END-IF.

OUTPUT-SECTION.
DISPLAY-RESULTS.
    DISPLAY '=== CUSTOMER REPORT ==='.
    DISPLAY 'Name: ' WS-CUST-NAME.
    DISPLAY 'Balance: ' WS-CUST-BALANCE.
    DISPLAY 'Credit Limit: ' WS-CUST-CREDIT-LIMIT.
    DISPLAY '=== END REPORT ==='.

Advanced Paragraph Control

IDENTIFICATION DIVISION.
PROGRAM-ID. ADV-PARAGRAPHS.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CHOICE PIC X.
   88 VALID-CHOICE VALUE '1' '2' '3' '4' 'X'.
   88 EXIT-CHOICE VALUE 'X'.
01 WS-NUMBER1 PIC 9(5).
01 WS-NUMBER2 PIC 9(5).
01 WS-RESULT PIC 9(6).
PROCEDURE DIVISION.
MAIN-MENU.
    PERFORM UNTIL EXIT-CHOICE
        DISPLAY '=== CALCULATOR MENU ==='
        DISPLAY '1. Add'
        DISPLAY '2. Subtract'
        DISPLAY '3. Multiply'
        DISPLAY '4. Divide'
        DISPLAY 'X. Exit'
        DISPLAY 'Enter choice:'
        ACCEPT WS-CHOICE
        
        EVALUATE WS-CHOICE
            WHEN '1' PERFORM ADD-NUMBERS
            WHEN '2' PERFORM SUBTRACT-NUMBERS
            WHEN '3' PERFORM MULTIPLY-NUMBERS
            WHEN '4' PERFORM DIVIDE-NUMBERS
            WHEN 'X' CONTINUE
            WHEN OTHER 
                DISPLAY 'Invalid choice, try again.'
        END-EVALUATE
    END-PERFORM.
    
    DISPLAY 'Goodbye!'.
    STOP RUN.

ADD-NUMBERS.
    PERFORM GET-INPUT-NUMBERS.
    COMPUTE WS-RESULT = WS-NUMBER1 + WS-NUMBER2.
    PERFORM DISPLAY-RESULT.

SUBTRACT-NUMBERS.
    PERFORM GET-INPUT-NUMBERS.
    COMPUTE WS-RESULT = WS-NUMBER1 - WS-NUMBER2.
    PERFORM DISPLAY-RESULT.

MULTIPLY-NUMBERS.
    PERFORM GET-INPUT-NUMBERS.
    COMPUTE WS-RESULT = WS-NUMBER1 * WS-NUMBER2.
    PERFORM DISPLAY-RESULT.

DIVIDE-NUMBERS.
    PERFORM GET-INPUT-NUMBERS.
    IF WS-NUMBER2 = 0
        DISPLAY 'Error: Cannot divide by zero!'
    ELSE
        COMPUTE WS-RESULT = WS-NUMBER1 / WS-NUMBER2
        PERFORM DISPLAY-RESULT
    END-IF.

GET-INPUT-NUMBERS.
    DISPLAY 'Enter first number:'.
    ACCEPT WS-NUMBER1.
    DISPLAY 'Enter second number:'.
    ACCEPT WS-NUMBER2.

DISPLAY-RESULT.
    DISPLAY 'Result: ' WS-RESULT.
    DISPLAY ''.

Common Pitfalls

  • Paragraph names must be unique within a section
  • Use sections to group related paragraphs
  • Avoid falling through to next paragraph unintentionally
  • Use PERFORM for controlled flow, GO TO sparingly

File Handling in COBOL

COBOL provides robust file handling capabilities for sequential, indexed, and relative files. File processing is essential for business applications.

Sequential File Processing

IDENTIFICATION DIVISION.
PROGRAM-ID. SEQ-FILE-DEMO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT CUSTOMER-FILE ASSIGN TO 'CUSTOMER.DAT'
        ORGANIZATION IS SEQUENTIAL
        ACCESS MODE IS SEQUENTIAL
        FILE STATUS IS FS-STATUS.

DATA DIVISION.
FILE SECTION.
FD CUSTOMER-FILE.
01 CUSTOMER-RECORD.
   05 CUST-ID PIC 9(5).
   05 CUST-NAME PIC X(20).
   05 CUST-BALANCE PIC 9(5)V99.

WORKING-STORAGE SECTION.
01 FS-STATUS PIC XX.
   88 FS-SUCCESS VALUE '00'.
   88 FS-EOF VALUE '10'.
01 WS-RECORD-COUNT PIC 999 VALUE 0.
PROCEDURE DIVISION.
MAIN-LOGIC.
    PERFORM OPEN-FILE.
    PERFORM READ-FILE.
    PERFORM CLOSE-FILE.
    STOP RUN.

OPEN-FILE.
    OPEN INPUT CUSTOMER-FILE.
    IF NOT FS-SUCCESS
        DISPLAY 'Error opening file: ' FS-STATUS
        STOP RUN
    END-IF.
    DISPLAY 'File opened successfully.'.

READ-FILE.
    PERFORM UNTIL FS-EOF
        READ CUSTOMER-FILE
            AT END CONTINUE
            NOT AT END
                ADD 1 TO WS-RECORD-COUNT
                DISPLAY 'Record ' WS-RECORD-COUNT ':'
                DISPLAY '  ID: ' CUST-ID
                DISPLAY '  Name: ' CUST-NAME
                DISPLAY '  Balance: ' CUST-BALANCE
        END-READ
    END-PERFORM.
    DISPLAY 'Total records read: ' WS-RECORD-COUNT.

CLOSE-FILE.
    CLOSE CUSTOMER-FILE.
    DISPLAY 'File closed.'.

Creating and Writing Files

IDENTIFICATION DIVISION.
PROGRAM-ID. CREATE-FILE-DEMO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT EMPLOYEE-FILE ASSIGN TO 'EMPLOYEE.DAT'
        ORGANIZATION IS SEQUENTIAL
        ACCESS MODE IS SEQUENTIAL
        FILE STATUS IS FS-STATUS.

DATA DIVISION.
FILE SECTION.
FD EMPLOYEE-FILE.
01 EMPLOYEE-RECORD.
   05 EMP-ID PIC 9(5).
   05 EMP-NAME PIC X(20).
   05 EMP-SALARY PIC 9(6)V99.

WORKING-STORAGE SECTION.
01 FS-STATUS PIC XX.
01 WS-I PIC 99.
PROCEDURE DIVISION.
MAIN-LOGIC.
    PERFORM CREATE-FILE.
    PERFORM WRITE-RECORDS.
    PERFORM CLOSE-FILE.
    STOP RUN.

CREATE-FILE.
    OPEN OUTPUT EMPLOYEE-FILE.
    IF NOT FS-SUCCESS
        DISPLAY 'Error creating file: ' FS-STATUS
        STOP RUN
    END-IF.
    DISPLAY 'File created for writing.'.

WRITE-RECORDS.
    PERFORM VARYING WS-I FROM 1 BY 1
        UNTIL WS-I > 5
        MOVE WS-I TO EMP-ID
        MOVE 'Employee ' TO EMP-NAME
        MOVE WS-I TO EMP-NAME(10:1)
        COMPUTE EMP-SALARY = WS-I * 10000.00
        
        WRITE EMPLOYEE-RECORD
        IF FS-SUCCESS
            DISPLAY 'Written: ' EMP-ID ' ' EMP-NAME 
                    ' ' EMP-SALARY
        ELSE
            DISPLAY 'Write error: ' FS-STATUS
        END-IF
    END-PERFORM.

CLOSE-FILE.
    CLOSE EMPLOYEE-FILE.
    DISPLAY 'File closed.'.

File Error Handling

IDENTIFICATION DIVISION.
PROGRAM-ID. FILE-ERROR-DEMO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT TRANSACTION-FILE ASSIGN TO 'TRANS.DAT'
        ORGANIZATION IS SEQUENTIAL
        FILE STATUS IS FS-STATUS.

DATA DIVISION.
FILE SECTION.
FD TRANSACTION-FILE.
01 TRANS-RECORD PIC X(80).

WORKING-STORAGE SECTION.
01 FS-STATUS PIC XX.
   88 FS-SUCCESS VALUE '00'.
   88 FS-EOF VALUE '10'.
   88 FS-INVALID-KEY VALUE '21' '22' '23' '24'.
   88 FS-PERMANENT-ERROR VALUE '30' '31' '34' '35' '37' '38' '39'.
   88 FS-LOGIC-ERROR VALUE '41' '42' '43' '44' '45' '46' '47' '48' '49'.

01 ERROR-MESSAGE PIC X(50).
PROCEDURE DIVISION.
MAIN-LOGIC.
    PERFORM OPEN-FILE.
    IF FS-SUCCESS
        PERFORM PROCESS-FILE
        PERFORM CLOSE-FILE
    ELSE
        PERFORM HANDLE-FILE-ERROR
    END-IF.
    STOP RUN.

OPEN-FILE.
    OPEN INPUT TRANSACTION-FILE.
    EVALUATE TRUE
        WHEN FS-SUCCESS
            DISPLAY 'File opened successfully'
        WHEN FS-PERMANENT-ERROR
            DISPLAY 'Permanent error opening file'
        WHEN OTHER
            DISPLAY 'Unexpected error opening file'
    END-EVALUATE.

PROCESS-FILE.
    PERFORM UNTIL FS-EOF OR FS-PERMANENT-ERROR
        READ TRANSACTION-FILE
            AT END CONTINUE
            NOT AT END
                DISPLAY 'Record: ' TRANS-RECORD
        END-READ
        
        IF NOT FS-SUCCESS AND NOT FS-EOF
            PERFORM HANDLE-READ-ERROR
        END-IF
    END-PERFORM.

HANDLE-FILE-ERROR.
    MOVE SPACES TO ERROR-MESSAGE.
    EVALUATE FS-STATUS
        WHEN '00' MOVE 'Success' TO ERROR-MESSAGE
        WHEN '10' MOVE 'End of file' TO ERROR-MESSAGE
        WHEN '30' MOVE 'Permanent error' TO ERROR-MESSAGE
        WHEN '35' MOVE 'File not found' TO ERROR-MESSAGE
        WHEN '37' MOVE 'Permission denied' TO ERROR-MESSAGE
        WHEN '41' MOVE 'File already open' TO ERROR-MESSAGE
        WHEN '42' MOVE 'File not open' TO ERROR-MESSAGE
        WHEN OTHER 
            STRING 'Unknown error: ' FS-STATUS 
                INTO ERROR-MESSAGE
    END-EVALUATE.
    DISPLAY 'File error: ' ERROR-MESSAGE.

HANDLE-READ-ERROR.
    DISPLAY 'Read error: ' FS-STATUS
    *> Attempt to continue or close file
    IF FS-PERMANENT-ERROR
        DISPLAY 'Cannot continue processing'
        PERFORM CLOSE-FILE
        STOP RUN
    END-IF.

CLOSE-FILE.
    CLOSE TRANSACTION-FILE.
    IF FS-SUCCESS
        DISPLAY 'File closed successfully'
    ELSE
        DISPLAY 'Error closing file: ' FS-STATUS
    END-IF.

Common Pitfalls

  • Always check FILE STATUS after file operations
  • Handle end-of-file conditions properly
  • Close files explicitly to avoid resource leaks
  • Use appropriate organization and access modes

DATA DIVISION in COBOL

The DATA DIVISION defines all data items used in a COBOL program. It's divided into sections for file descriptions, working storage, and linkage data.

Complete DATA DIVISION Structure

IDENTIFICATION DIVISION.
PROGRAM-ID. DATA-DIVISION-DEMO.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SOURCE-COMPUTER. IBM-370.
OBJECT-COMPUTER. IBM-370.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT MASTER-FILE ASSIGN TO 'MASTER.DAT'.
    SELECT REPORT-FILE ASSIGN TO 'REPORT.DAT'.

DATA DIVISION.
FILE SECTION.
FD MASTER-FILE
    RECORD CONTAINS 80 CHARACTERS
    BLOCK CONTAINS 10 RECORDS.
01 MASTER-RECORD.
   05 M-CUST-ID PIC 9(5).
   05 M-CUST-NAME PIC X(20).
   05 M-CUST-ADDRESS PIC X(30).
   05 M-CUST-BALANCE PIC 9(6)V99.
   05 FILLER PIC X(17).

FD REPORT-FILE
    RECORD CONTAINS 132 CHARACTERS.
01 REPORT-RECORD PIC X(132).

WORKING-STORAGE SECTION.
01 WS-CONTROL-FIELDS.
   05 WS-RECORD-COUNT PIC 9(5) VALUE ZERO.
   05 WS-TOTAL-BALANCE PIC 9(8)V99 VALUE ZERO.
   05 WS-AVERAGE-BALANCE PIC 9(6)V99 VALUE ZERO.
   05 WS-FILE-STATUS PIC XX VALUE '00'.
      88 WS-SUCCESS VALUE '00'.
      88 WS-EOF VALUE '10'.

01 WS-CURRENT-DATE.
   05 WS-YEAR PIC 9999.
   05 WS-MONTH PIC 99.
   05 WS-DAY PIC 99.

01 WS-REPORT-HEADER.
   05 FILLER PIC X(20) VALUE 'CUSTOMER REPORT'.
   05 FILLER PIC X(10) VALUE SPACES.
   05 FILLER PIC X(6) VALUE 'DATE:'.
   05 WS-HEADER-DATE PIC 99/99/9999.

LINKAGE SECTION.
01 LS-PARAMETERS.
   05 LS-COMPANY-NAME PIC X(20).
   05 LS-REPORT-TYPE PIC X.
   05 LS-PROCESS-DATE PIC 9(8).

PROCEDURE DIVISION.
MAIN-LOGIC.
    DISPLAY 'DATA DIVISION demonstration'.
    STOP RUN.

Working-Storage Examples

IDENTIFICATION DIVISION.
PROGRAM-ID. WORKING-STORAGE-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
*> Elementary items
01 WS-EMPLOYEE-DATA.
   05 WS-EMP-ID PIC 9(5) VALUE 12345.
   05 WS-EMP-NAME PIC X(20) VALUE 'JOHN SMITH'.
   05 WS-EMP-SALARY PIC 9(6)V99 VALUE 55000.00.
   05 WS-EMP-DEPT PIC X(10) VALUE 'SALES'.
   05 WS-EMP-ACTIVE PIC X VALUE 'Y'.
      88 ACTIVE-EMPLOYEE VALUE 'Y'.
      88 INACTIVE-EMPLOYEE VALUE 'N'.

*> Group items and redefines
01 WS-DATE-FIELDS.
   05 WS-DATE-NUMERIC PIC 9(8) VALUE 20240315.
   05 WS-DATE-BREAKDOWN REDEFINES WS-DATE-NUMERIC.
      10 WS-DATE-YEAR PIC 9(4).
      10 WS-DATE-MONTH PIC 9(2).
      10 WS-DATE-DAY PIC 9(2).

*> Tables/arrays
01 WS-SALES-TABLE.
   05 WS-SALES-REGION OCCURS 4 TIMES
      INDEXED BY REGION-INDEX.
      10 WS-REGION-NAME PIC X(15).
      10 WS-REGION-SALES PIC 9(7)V99 OCCURS 12 TIMES
         INDEXED BY MONTH-INDEX.

*> Constants and literals
01 WS-CONSTANTS.
   05 WS-PI PIC 9V9(5) VALUE 3.14159.
   05 WS-TAX-RATE PIC V999 VALUE .0825.
   05 WS-MAX-EMPLOYEES PIC 999 VALUE 500.
   05 WS-COMPANY-NAME PIC X(25) 
         VALUE 'ABC CORPORATION'.

*> Conditional data items
01 WS-ERROR-CODES.
   05 WS-ERROR-CODE PIC X(2).
      88 VALID-CODE VALUE '00' '01' '02'.
      88 INVALID-CODE VALUE '99'.
   05 WS-ERROR-MESSAGE PIC X(40).

PROCEDURE DIVISION.
MAIN-LOGIC.
    DISPLAY 'Employee: ' WS-EMP-NAME.
    DISPLAY 'Salary: ' WS-EMP-SALARY.
    
    MOVE WS-DATE-NUMERIC TO WS-DATE-BREAKDOWN.
    DISPLAY 'Date: ' WS-DATE-MONTH '/' 
            WS-DATE-DAY '/' WS-DATE-YEAR.
    
    IF ACTIVE-EMPLOYEE
        DISPLAY 'Employee is active'
    END-IF.
    
    STOP RUN.

Advanced Data Definitions

IDENTIFICATION DIVISION.
PROGRAM-ID. ADV-DATA-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
*> Usage clauses for efficiency
01 WS-COMPUTATIONAL-DATA.
   05 WS-BINARY-NUMBER PIC 9(5) USAGE COMP VALUE 100.
   05 WS-PACKED-NUMBER PIC 9(5) USAGE COMP-3 VALUE 200.
   05 WS-DISPLAY-NUMBER PIC 9(5) USAGE DISPLAY VALUE 300.

*> Synchronized data for alignment
01 WS-ALIGNED-DATA.
   05 WS-FIELD-A PIC X(10).
   05 WS-FIELD-B PIC 9(5) SYNCHRONIZED RIGHT.
   05 WS-FIELD-C PIC X(15).

*> Dynamic length fields
01 WS-VARIABLE-DATA.
   05 WS-NAME-LENGTH PIC 99.
   05 WS-CUSTOMER-NAME PIC X(50).

*> Table with occurs depending on
01 WS-DYNAMIC-TABLE.
   05 WS-TABLE-SIZE PIC 99 VALUE 5.
   05 WS-DATA-ENTRY OCCURS 1 TO 50 TIMES
      DEPENDING ON WS-TABLE-SIZE
      INDEXED BY DATA-INDEX.
      10 WS-DATA-VALUE PIC 9(5).
      10 WS-DATA-DESC PIC X(20).

*> Special data types
01 WS-SPECIAL-FIELDS.
   05 WS-POINTER-FIELD USAGE IS POINTER.
   05 WS-PROC-POINTER USAGE IS PROCEDURE-POINTER.
   05 WS-INDEX-FIELD USAGE IS INDEX.

PROCEDURE DIVISION.
MAIN-LOGIC.
    DISPLAY 'Computational data demonstration'.
    
    *> Initialize dynamic table
    PERFORM VARYING DATA-INDEX FROM 1 BY 1
        UNTIL DATA-INDEX > WS-TABLE-SIZE
        COMPUTE WS-DATA-VALUE(DATA-INDEX) = DATA-INDEX * 10
        MOVE 'Description' TO WS-DATA-DESC(DATA-INDEX)
        MOVE DATA-INDEX TO WS-DATA-DESC(12:2)
    END-PERFORM.
    
    *> Display table contents
    PERFORM VARYING DATA-INDEX FROM 1 BY 1
        UNTIL DATA-INDEX > WS-TABLE-SIZE
        DISPLAY 'Entry ' DATA-INDEX ': ' 
                WS-DATA-VALUE(DATA-INDEX) ' '
                WS-DATA-DESC(DATA-INDEX)
    END-PERFORM.
    
    STOP RUN.

Common Pitfalls

  • Define data items before using them in PROCEDURE DIVISION
  • Use appropriate USAGE clauses for efficiency
  • Initialize working-storage variables properly
  • Understand the difference between DISPLAY and COMPUTATIONAL usage

Report Writer in COBOL

The Report Writer feature provides powerful, declarative reporting capabilities, automating much of the formatting and control break logic needed for business reports.

Basic Report Writer Setup

IDENTIFICATION DIVISION.
PROGRAM-ID. REPORT-DEMO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT SALES-FILE ASSIGN TO 'SALES.DAT'.
    SELECT REPORT-FILE ASSIGN TO 'SALES.RPT'.

DATA DIVISION.
FILE SECTION.
FD SALES-FILE.
01 SALES-RECORD.
   05 SR-REGION PIC X(10).
   05 SR-SALESMAN PIC X(15).
   05 SR-AMOUNT PIC 9(6)V99.

FD REPORT-FILE
    REPORT IS SALES-REPORT.

WORKING-STORAGE SECTION.
01 WS-EOF-FLAG PIC X VALUE 'N'.
   88 END-OF-FILE VALUE 'Y'.

REPORT SECTION.
RD SALES-REPORT
    CONTROLS ARE SR-REGION, SR-SALESMAN
    PAGE LIMIT IS 60 LINES
    HEADING 1
    FIRST DETAIL 5
    LAST DETAIL 40.

01 REPORT-HEADING TYPE PAGE HEADING.
   05 LINE 1.
      10 COLUMN 25 PIC X(30) 
         VALUE 'SALES REPORT BY REGION'.
   05 LINE 2.
      10 COLUMN 25 PIC X(30) 
         VALUE '=============================='.

01 REGION-HEADING TYPE CONTROL HEADING SR-REGION.
   05 LINE PLUS 2.
      10 COLUMN 5 PIC X(7) VALUE 'REGION:'.
      10 COLUMN 13 PIC X(10) SOURCE SR-REGION.

01 SALESMAN-HEADING TYPE CONTROL HEADING SR-SALESMAN.
   05 LINE PLUS 1.
      10 COLUMN 10 PIC X(9) VALUE 'SALESMAN:'.
      10 COLUMN 20 PIC X(15) SOURCE SR-SALESMAN.

01 DETAIL-LINE TYPE DETAIL.
   05 LINE PLUS 1.
      10 COLUMN 10 PIC X(6) VALUE 'SALES:'.
      10 COLUMN 20 PIC $$$,$$9.99 SOURCE SR-AMOUNT.

01 REGION-TOTAL TYPE CONTROL FOOTING SR-REGION.
   05 LINE PLUS 2.
      10 COLUMN 10 PIC X(13) 
         VALUE 'REGION TOTAL:'.
      10 COLUMN 25 PIC $$$,$$$,$$9.99 
         SUM SR-AMOUNT.

01 FINAL-TOTAL TYPE CONTROL FOOTING FINAL.
   05 LINE PLUS 3.
      10 COLUMN 10 PIC X(12) 
         VALUE 'GRAND TOTAL:'.
      10 COLUMN 25 PIC $$$,$$$,$$9.99 
         SUM SR-AMOUNT.

PROCEDURE DIVISION.
MAIN-LOGIC.
    OPEN INPUT SALES-FILE
         OUTPUT REPORT-FILE.
    
    INITIATE SALES-REPORT.
    PERFORM UNTIL END-OF-FILE
        READ SALES-FILE
            AT END SET END-OF-FILE TO TRUE
            NOT AT END
                GENERATE DETAIL-LINE
        END-READ
    END-PERFORM.
    
    TERMINATE SALES-REPORT.
    CLOSE SALES-FILE REPORT-FILE.
    STOP RUN.

Advanced Report Features

IDENTIFICATION DIVISION.
PROGRAM-ID. ADV-REPORT-DEMO.
DATA DIVISION.
FILE SECTION.
FD EMPLOYEE-FILE.
01 EMPLOYEE-RECORD.
   05 ER-DEPT PIC X(10).
   05 ER-NAME PIC X(20).
   05 ER-SALARY PIC 9(6)V99.
   05 ER-HIRE-DATE PIC 9(8).

FD REPORT-FILE
    REPORT IS EMP-REPORT.

WORKING-STORAGE SECTION.
01 WS-CURRENT-DATE.
   05 WS-YEAR PIC 9999.
   05 WS-MONTH PIC 99.
   05 WS-DAY PIC 99.

REPORT SECTION.
RD EMP-REPORT
    CONTROLS ARE ER-DEPT
    PAGE LIMIT IS 66 LINES
    HEADING 1
    FIRST DETAIL 6
    LAST DETAIL 55
    FOOTING 60.

01 PAGE-HEADER TYPE PAGE HEADING.
   05 LINE 1.
      10 COLUMN 20 PIC X(25) 
         VALUE 'EMPLOYEE SALARY REPORT'.
      10 COLUMN 60 PIC X(6) VALUE 'PAGE:'.
      10 COLUMN 67 PIC Z9 SOURCE PAGE-COUNTER.
   05 LINE 2.
      10 COLUMN 20 PIC X(25) 
         VALUE '========================='.
   05 LINE 4.
      10 COLUMN 5 PIC X(10) VALUE 'DATE:'.
      10 COLUMN 16 PIC 99/99/9999 
         SOURCE WS-MONTH WS-DAY WS-YEAR.

01 DEPT-HEADER TYPE CONTROL HEADING ER-DEPT.
   05 LINE PLUS 2.
      10 COLUMN 5 PIC X(11) VALUE 'DEPARTMENT:'.
      10 COLUMN 17 PIC X(10) SOURCE ER-DEPT.
   05 LINE PLUS 1.
      10 COLUMN 5 PIC X(20) 
         VALUE '--------------------'.
   05 LINE PLUS 1.
      10 COLUMN 5 PIC X(4) VALUE 'NAME'.
      10 COLUMN 25 PIC X(6) VALUE 'SALARY'.
      10 COLUMN 40 PIC X(10) VALUE 'HIRE DATE'.

01 EMP-DETAIL TYPE DETAIL.
   05 LINE PLUS 1.
      10 COLUMN 5 PIC X(20) SOURCE ER-NAME.
      10 COLUMN 25 PIC $$$,$$9.99 SOURCE ER-SALARY.
      10 COLUMN 40 PIC 99/99/9999 
         SOURCE ER-HIRE-DATE(5:2) '/' 
                ER-HIRE-DATE(7:2) '/' 
                ER-HIRE-DATE(1:4).

01 DEPT-SUMMARY TYPE CONTROL FOOTING ER-DEPT.
   05 LINE PLUS 2.
      10 COLUMN 5 PIC X(18) 
         VALUE 'DEPARTMENT TOTAL:'.
      10 COLUMN 25 PIC $$$,$$$,$$9.99 
         SUM ER-SALARY.
   05 LINE PLUS 1.
      10 COLUMN 5 PIC X(18) 
         VALUE 'AVERAGE SALARY:'.
      10 COLUMN 25 PIC $$$,$$9.99 
         SUM ER-SALARY UPON ER-DEPT.

01 REPORT-FOOTER TYPE CONTROL FOOTING FINAL.
   05 LINE PLUS 3.
      10 COLUMN 5 PIC X(13) 
         VALUE 'GRAND TOTAL:'.
      10 COLUMN 25 PIC $$$,$$$,$$9.99 
         SUM ER-SALARY.
   05 LINE PLUS 1.
      10 COLUMN 5 PIC X(13) 
         VALUE 'REPORT END'.
   05 LINE PLUS 1.
      10 COLUMN 5 PIC X(30) 
         VALUE '=============================='.

PROCEDURE DIVISION.
MAIN-LOGIC.
    MOVE FUNCTION CURRENT-DATE(1:8) TO WS-CURRENT-DATE.
    OPEN INPUT EMPLOYEE-FILE
         OUTPUT REPORT-FILE.
    
    INITIATE EMP-REPORT.
    PERFORM UNTIL END-OF-FILE
        READ EMPLOYEE-FILE
            AT END SET END-OF-FILE TO TRUE
            NOT AT END
                GENERATE EMP-DETAIL
        END-READ
    END-PERFORM.
    
    TERMINATE EMP-REPORT.
    CLOSE EMPLOYEE-FILE REPORT-FILE.
    STOP RUN.

Common Pitfalls

  • Always use INITIATE before GENERATE and TERMINATE after
  • Define CONTROLS properly for control break processing
  • Use PAGE LIMIT to manage page breaks
  • Test reports with various data volumes

Printing in COBOL

COBOL provides various methods for generating printed output, from simple DISPLAY statements to sophisticated report formatting for physical printers.

Basic Printing with DISPLAY

IDENTIFICATION DIVISION.
PROGRAM-ID. PRINTING-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-EMPLOYEE-DATA.
   05 WS-EMP-NAME PIC X(20) VALUE 'JOHN SMITH'.
   05 WS-EMP-SALARY PIC 9(6)V99 VALUE 55000.00.
   05 WS-EMP-DEPT PIC X(10) VALUE 'SALES'.

01 WS-PRINT-LINE PIC X(80).
01 WS-PAGE-COUNT PIC 999 VALUE 1.
01 WS-LINE-COUNT PIC 999.
01 WS-MAX-LINES PIC 999 VALUE 60.
PROCEDURE DIVISION.
MAIN-LOGIC.
    PERFORM PRINT-HEADER.
    PERFORM PRINT-EMPLOYEE-DATA.
    PERFORM PRINT-FOOTER.
    STOP RUN.

PRINT-HEADER.
    MOVE ALL '=' TO WS-PRINT-LINE.
    DISPLAY WS-PRINT-LINE.
    
    MOVE SPACES TO WS-PRINT-LINE.
    STRING 'EMPLOYEE REPORT' 
           ' PAGE: ' WS-PAGE-COUNT
        INTO WS-PRINT-LINE.
    DISPLAY WS-PRINT-LINE.
    
    MOVE ALL '-' TO WS-PRINT-LINE.
    DISPLAY WS-PRINT-LINE.
    
    ADD 3 TO WS-LINE-COUNT.

PRINT-EMPLOYEE-DATA.
    *> Check for page break
    IF WS-LINE-COUNT > WS-MAX-LINES
        PERFORM PRINT-FOOTER
        ADD 1 TO WS-PAGE-COUNT
        MOVE 0 TO WS-LINE-COUNT
        PERFORM PRINT-HEADER
    END-IF.
    
    MOVE SPACES TO WS-PRINT-LINE.
    STRING 'NAME: ' WS-EMP-NAME
        INTO WS-PRINT-LINE.
    DISPLAY WS-PRINT-LINE.
    
    MOVE SPACES TO WS-PRINT-LINE.
    STRING 'SALARY: $' WS-EMP-SALARY
        INTO WS-PRINT-LINE.
    DISPLAY WS-PRINT-LINE.
    
    MOVE SPACES TO WS-PRINT-LINE.
    STRING 'DEPARTMENT: ' WS-EMP-DEPT
        INTO WS-PRINT-LINE.
    DISPLAY WS-PRINT-LINE.
    
    ADD 3 TO WS-LINE-COUNT.

PRINT-FOOTER.
    DISPLAY ' '.
    MOVE ALL '=' TO WS-PRINT-LINE.
    DISPLAY WS-PRINT-LINE.
    DISPLAY 'END OF REPORT'.

Advanced Print Formatting

IDENTIFICATION DIVISION.
PROGRAM-ID. ADV-PRINTING.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-PRINT-CONTROLS.
   05 WS-PAGE-NUMBER PIC 999 VALUE 1.
   05 WS-LINE-NUMBER PIC 999 VALUE 0.
   05 WS-LINES-PER-PAGE PIC 999 VALUE 55.
   05 WS-CURRENT-DATE PIC 9(8).
   05 WS-CURRENT-TIME PIC 9(6).

01 WS-REPORT-LINE.
   05 FILLER PIC X(5) VALUE SPACES.
   05 WS-RL-CONTENT PIC X(70).
   05 FILLER PIC X(5) VALUE SPACES.

01 WS-HEADER-LINE.
   05 FILLER PIC X(20) VALUE 'FINANCIAL REPORT'.
   05 FILLER PIC X(30) VALUE SPACES.
   05 FILLER PIC X(6) VALUE 'PAGE:'.
   05 WS-HL-PAGE-NUM PIC ZZZ.
   05 FILLER PIC X(15) VALUE SPACES.

01 WS-DETAIL-LINE.
   05 FILLER PIC X(10) VALUE SPACES.
   05 WS-DL-DESCRIPTION PIC X(20).
   05 WS-DL-AMOUNT PIC $$$,$$$,$$9.99.
   05 FILLER PIC X(40) VALUE SPACES.

01 WS-TOTAL-LINE.
   05 FILLER PIC X(10) VALUE SPACES.
   05 FILLER PIC X(10) VALUE 'TOTAL:'.
   05 WS-TL-AMOUNT PIC $$$,$$$,$$9.99.
   05 FILLER PIC X(45) VALUE SPACES.

PROCEDURE DIVISION.
MAIN-LOGIC.
    PERFORM INITIALIZE-PRINT.
    PERFORM PRINT-REPORT.
    PERFORM FINALIZE-PRINT.
    STOP RUN.

INITIALIZE-PRINT.
    MOVE FUNCTION CURRENT-DATE(1:8) TO WS-CURRENT-DATE.
    MOVE FUNCTION CURRENT-DATE(9:6) TO WS-CURRENT-TIME.
    DISPLAY 'REPORT STARTED AT: ' 
            WS-CURRENT-DATE(5:2) '/' 
            WS-CURRENT-DATE(7:2) '/' 
            WS-CURRENT-DATE(1:4) ' '
            WS-CURRENT-TIME(1:2) ':' 
            WS-CURRENT-TIME(3:2) ':' 
            WS-CURRENT-TIME(5:2).

PRINT-REPORT.
    PERFORM PRINT-HEADER.
    
    *> Print sample data
    MOVE 'SALES REVENUE' TO WS-DL-DESCRIPTION.
    MOVE 150000.50 TO WS-DL-AMOUNT.
    PERFORM PRINT-DETAIL.
    
    MOVE 'OPERATING COSTS' TO WS-DL-DESCRIPTION.
    MOVE -75000.25 TO WS-DL-AMOUNT.
    PERFORM PRINT-DETAIL.
    
    MOVE 'NET INCOME' TO WS-DL-DESCRIPTION.
    MOVE 75000.25 TO WS-TL-AMOUNT.
    PERFORM PRINT-TOTAL.

PRINT-HEADER.
    IF WS-LINE-NUMBER > 0
        PERFORM FORM-FEED
    END-IF.
    
    MOVE WS-PAGE-NUMBER TO WS-HL-PAGE-NUM.
    DISPLAY WS-HEADER-LINE.
    DISPLAY ' '.
    DISPLAY 'DATE: ' WS-CURRENT-DATE(5:2) '/' 
                      WS-CURRENT-DATE(7:2) '/' 
                      WS-CURRENT-DATE(1:4).
    DISPLAY ' '.
    ADD 4 TO WS-LINE-NUMBER.

PRINT-DETAIL.
    IF WS-LINE-NUMBER >= WS-LINES-PER-PAGE
        ADD 1 TO WS-PAGE-NUMBER
        MOVE 0 TO WS-LINE-NUMBER
        PERFORM PRINT-HEADER
    END-IF.
    
    DISPLAY WS-DETAIL-LINE.
    ADD 1 TO WS-LINE-NUMBER.

PRINT-TOTAL.
    DISPLAY ' '.
    DISPLAY ALL '-'.
    DISPLAY WS-TOTAL-LINE.
    DISPLAY ALL '='.
    ADD 4 TO WS-LINE-NUMBER.

FORM-FEED.
    *> Simulate form feed - actual implementation varies
    DISPLAY ' '.
    DISPLAY '=== PAGE BREAK ==='.
    DISPLAY ' '.

FINALIZE-PRINT.
    DISPLAY ' '.
    DISPLAY '*** END OF REPORT ***'.
    DISPLAY ' '.

Common Pitfalls

  • Manage line counts manually for page breaks
  • Use proper editing characters for numeric fields
  • Handle negative numbers appropriately in financial reports
  • Test print formatting with various data sizes

VSAM Files in COBOL

VSAM (Virtual Storage Access Method) is an IBM file management system that provides efficient indexed and sequential access to data.

VSAM KSDS (Key Sequenced Data Set)

IDENTIFICATION DIVISION.
PROGRAM-ID. VSAM-KSDS-DEMO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT CUSTOMER-FILE ASSIGN TO CUSTOMER
        ORGANIZATION IS INDEXED
        ACCESS MODE IS SEQUENTIAL
        RECORD KEY IS CUST-KEY
        FILE STATUS IS FS-STATUS.

DATA DIVISION.
FILE SECTION.
FD CUSTOMER-FILE.
01 CUSTOMER-RECORD.
   05 CUST-KEY PIC 9(5).
   05 CUST-NAME PIC X(20).
   05 CUST-ADDRESS PIC X(30).
   05 CUST-BALANCE PIC 9(6)V99.

WORKING-STORAGE SECTION.
01 FS-STATUS PIC XX.
   88 FS-SUCCESS VALUE '00'.
   88 FS-DUPLICATE VALUE '22'.
   88 FS-NOTFOUND VALUE '23'.
   88 FS-EOF VALUE '10'.

01 WS-COMMAND PIC X.
   88 ADD-COMMAND VALUE 'A'.
   88 READ-COMMAND VALUE 'R'.
   88 UPDATE-COMMAND VALUE 'U'.
   88 DELETE-COMMAND VALUE 'D'.
   88 EXIT-COMMAND VALUE 'X'.

01 WS-SEARCH-KEY PIC 9(5).
PROCEDURE DIVISION.
MAIN-LOGIC.
    PERFORM OPEN-FILE.
    PERFORM PROCESS-COMMANDS UNTIL EXIT-COMMAND.
    PERFORM CLOSE-FILE.
    STOP RUN.

OPEN-FILE.
    OPEN I-O CUSTOMER-FILE.
    IF NOT FS-SUCCESS
        DISPLAY 'Error opening VSAM file: ' FS-STATUS
        STOP RUN
    END-IF.
    DISPLAY 'VSAM file opened successfully.'.

PROCESS-COMMANDS.
    DISPLAY 'Enter command (A=Add, R=Read, U=Update, D=Delete, X=Exit):'.
    ACCEPT WS-COMMAND.
    
    EVALUATE TRUE
        WHEN ADD-COMMAND PERFORM ADD-RECORD
        WHEN READ-COMMAND PERFORM READ-RECORD
        WHEN UPDATE-COMMAND PERFORM UPDATE-RECORD
        WHEN DELETE-COMMAND PERFORM DELETE-RECORD
        WHEN EXIT-COMMAND DISPLAY 'Exiting...'
        WHEN OTHER DISPLAY 'Invalid command'
    END-EVALUATE.

ADD-RECORD.
    DISPLAY 'Enter customer key:'.
    ACCEPT CUST-KEY.
    DISPLAY 'Enter customer name:'.
    ACCEPT CUST-NAME.
    DISPLAY 'Enter customer address:'.
    ACCEPT CUST-ADDRESS.
    DISPLAY 'Enter customer balance:'.
    ACCEPT CUST-BALANCE.
    
    WRITE CUSTOMER-RECORD.
    IF FS-SUCCESS
        DISPLAY 'Record added successfully.'
    ELSE
        DISPLAY 'Error adding record: ' FS-STATUS
    END-IF.

READ-RECORD.
    DISPLAY 'Enter customer key to read:'.
    ACCEPT WS-SEARCH-KEY.
    
    MOVE WS-SEARCH-KEY TO CUST-KEY.
    READ CUSTOMER-FILE KEY IS CUST-KEY.
    IF FS-SUCCESS
        DISPLAY 'Record found:'
        DISPLAY '  Key: ' CUST-KEY
        DISPLAY '  Name: ' CUST-NAME
        DISPLAY '  Address: ' CUST-ADDRESS
        DISPLAY '  Balance: ' CUST-BALANCE
    ELSE
        DISPLAY 'Record not found: ' FS-STATUS
    END-IF.

UPDATE-RECORD.
    DISPLAY 'Enter customer key to update:'.
    ACCEPT WS-SEARCH-KEY.
    
    MOVE WS-SEARCH-KEY TO CUST-KEY.
    READ CUSTOMER-FILE KEY IS CUST-KEY.
    IF FS-SUCCESS
        DISPLAY 'Current name: ' CUST-NAME
        DISPLAY 'Enter new name:'.
        ACCEPT CUST-NAME
        DISPLAY 'Enter new balance:'.
        ACCEPT CUST-BALANCE
        
        REWRITE CUSTOMER-RECORD
        IF FS-SUCCESS
            DISPLAY 'Record updated successfully.'
        ELSE
            DISPLAY 'Error updating record: ' FS-STATUS
        END-IF
    ELSE
        DISPLAY 'Record not found for update: ' FS-STATUS
    END-IF.

DELETE-RECORD.
    DISPLAY 'Enter customer key to delete:'.
    ACCEPT WS-SEARCH-KEY.
    
    MOVE WS-SEARCH-KEY TO CUST-KEY.
    DELETE CUSTOMER-FILE.
    IF FS-SUCCESS
        DISPLAY 'Record deleted successfully.'
    ELSE
        DISPLAY 'Error deleting record: ' FS-STATUS
    END-IF.

CLOSE-FILE.
    CLOSE CUSTOMER-FILE.
    DISPLAY 'VSAM file closed.'.

VSAM Random Access

IDENTIFICATION DIVISION.
PROGRAM-ID. VSAM-RANDOM-DEMO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT PRODUCT-FILE ASSIGN TO PRODUCT
        ORGANIZATION IS INDEXED
        ACCESS MODE IS RANDOM
        RECORD KEY IS PROD-KEY
        FILE STATUS IS FS-STATUS.

DATA DIVISION.
FILE SECTION.
FD PRODUCT-FILE.
01 PRODUCT-RECORD.
   05 PROD-KEY PIC X(5).
   05 PROD-DESCRIPTION PIC X(30).
   05 PROD-PRICE PIC 9(5)V99.
   05 PROD-QUANTITY PIC 9(5).

WORKING-STORAGE SECTION.
01 FS-STATUS PIC XX.
01 WS-SEARCH-KEY PIC X(5).
01 WS-START-KEY PIC X(5).
01 WS-END-KEY PIC X(5).
PROCEDURE DIVISION.
MAIN-LOGIC.
    PERFORM OPEN-FILE.
    PERFORM RANDOM-ACCESS.
    PERFORM SEQUENTIAL-ACCESS.
    PERFORM CLOSE-FILE.
    STOP RUN.

OPEN-FILE.
    OPEN I-O PRODUCT-FILE.
    IF NOT FS-SUCCESS
        DISPLAY 'Error opening VSAM file: ' FS-STATUS
        STOP RUN
    END-IF.

RANDOM-ACCESS.
    DISPLAY '=== RANDOM ACCESS DEMO ==='.
    MOVE 'A1001' TO WS-SEARCH-KEY.
    PERFORM READ-RANDOM-RECORD.
    
    MOVE 'B2002' TO WS-SEARCH-KEY.
    PERFORM READ-RANDOM-RECORD.
    
    MOVE 'XXXXX' TO WS-SEARCH-KEY.
    PERFORM READ-RANDOM-RECORD.

READ-RANDOM-RECORD.
    MOVE WS-SEARCH-KEY TO PROD-KEY.
    READ PRODUCT-FILE.
    IF FS-SUCCESS
        DISPLAY 'Found: ' PROD-KEY ' - ' PROD-DESCRIPTION
    ELSE
        DISPLAY 'Not found: ' WS-SEARCH-KEY ' - ' FS-STATUS
    END-IF.

SEQUENTIAL-ACCESS.
    DISPLAY '=== SEQUENTIAL ACCESS DEMO ==='.
    MOVE 'A1000' TO WS-START-KEY.
    MOVE 'A1999' TO WS-END-KEY.
    
    MOVE WS-START-KEY TO PROD-KEY.
    START PRODUCT-FILE KEY >= PROD-KEY.
    IF FS-SUCCESS
        PERFORM UNTIL FS-EOF OR PROD-KEY > WS-END-KEY
            READ PRODUCT-FILE NEXT
                AT END CONTINUE
                NOT AT END
                    DISPLAY 'Seq: ' PROD-KEY ' - ' 
                            PROD-DESCRIPTION
            END-READ
        END-PERFORM
    ELSE
        DISPLAY 'Start failed: ' FS-STATUS
    END-IF.

CLOSE-FILE.
    CLOSE PRODUCT-FILE.
    DISPLAY 'VSAM file closed.'.

Common Pitfalls

  • Always check FILE STATUS after VSAM operations
  • Use appropriate ACCESS MODE for your needs
  • Handle duplicate keys properly in KSDS
  • Use START for positioned sequential reading

DB2 in COBOL

COBOL can interact with IBM DB2 databases using embedded SQL, allowing powerful database operations within COBOL programs.

Basic DB2 Program Structure

IDENTIFICATION DIVISION.
PROGRAM-ID. DB2-BASIC-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
*> SQL communication area
EXEC SQL
    INCLUDE SQLCA
END-EXEC.

*> Host variables for database interaction
EXEC SQL
    INCLUDE CUSTOMER-RECORD
END-EXEC.

01 WS-CUSTOMER-DATA.
   05 WS-CUST-ID PIC 9(5).
   05 WS-CUST-NAME PIC X(20).
   05 WS-CUST-BALANCE PIC 9(6)V99.
   05 WS-CUST-CREDIT-LIMIT PIC 9(6)V99.

01 WS-SQLCODE-DISPLAY PIC ----9.
01 WS-EOF-FLAG PIC X VALUE 'N'.
   88 END-OF-DATA VALUE 'Y'.
PROCEDURE DIVISION.
MAIN-LOGIC.
    DISPLAY 'DB2 COBOL Program Started'.
    
    PERFORM CONNECT-DB2.
    PERFORM PROCESS-CUSTOMERS.
    PERFORM DISCONNECT-DB2.
    
    DISPLAY 'DB2 COBOL Program Completed'.
    STOP RUN.

CONNECT-DB2.
    EXEC SQL
        CONNECT TO SAMPLEDB
    END-EXEC.
    
    IF SQLCODE = 0
        DISPLAY 'Successfully connected to DB2'
    ELSE
        DISPLAY 'DB2 connection failed: ' SQLCODE
        STOP RUN
    END-IF.

PROCESS-CUSTOMERS.
    EXEC SQL
        DECLARE CUST-CURSOR CURSOR FOR
        SELECT CUST_ID, CUST_NAME, BALANCE, CREDIT_LIMIT
        FROM CUSTOMER
        WHERE BALANCE > 1000
        ORDER BY CUST_ID
    END-EXEC.
    
    EXEC SQL
        OPEN CUST-CURSOR
    END-EXEC.
    
    IF SQLCODE = 0
        PERFORM UNTIL END-OF-DATA
            EXEC SQL
                FETCH CUST-CURSOR INTO
                    :WS-CUST-ID,
                    :WS-CUST-NAME,
                    :WS-CUST-BALANCE,
                    :WS-CUST-CREDIT-LIMIT
            END-EXEC
            
            EVALUATE SQLCODE
                WHEN 0
                    DISPLAY 'Customer: ' WS-CUST-ID 
                            ' ' WS-CUST-NAME
                            ' Balance: ' WS-CUST-BALANCE
                WHEN 100
                    SET END-OF-DATA TO TRUE
                WHEN OTHER
                    DISPLAY 'Fetch error: ' SQLCODE
                    SET END-OF-DATA TO TRUE
            END-EVALUATE
        END-PERFORM
        
        EXEC SQL
            CLOSE CUST-CURSOR
        END-EXEC
    ELSE
        DISPLAY 'Cursor open failed: ' SQLCODE
    END-IF.

DISCONNECT-DB2.
    EXEC SQL
        CONNECT RESET
    END-EXEC.
    DISPLAY 'Disconnected from DB2'.

DB2 Data Manipulation

IDENTIFICATION DIVISION.
PROGRAM-ID. DB2-DML-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL
    INCLUDE SQLCA
END-EXEC.

EXEC SQL
    INCLUDE CUSTOMER-RECORD
END-EXEC.

01 WS-CUSTOMER-DATA.
   05 WS-CUST-ID PIC 9(5).
   05 WS-CUST-NAME PIC X(20).
   05 WS-CUST-BALANCE PIC 9(6)V99.
   05 WS-CUST-CREDIT-LIMIT PIC 9(6)V99.

01 WS-UPDATE-COUNT PIC S9(5).
01 WS-DELETE-COUNT PIC S9(5).
PROCEDURE DIVISION.
MAIN-LOGIC.
    PERFORM CONNECT-DB2.
    PERFORM INSERT-CUSTOMER.
    PERFORM UPDATE-CUSTOMERS.
    PERFORM DELETE-CUSTOMER.
    PERFORM DISCONNECT-DB2.
    STOP RUN.

INSERT-CUSTOMER.
    MOVE 10001 TO WS-CUST-ID.
    MOVE 'JOHN SMITH' TO WS-CUST-NAME.
    MOVE 5000.00 TO WS-CUST-BALANCE.
    MOVE 10000.00 TO WS-CUST-CREDIT-LIMIT.
    
    EXEC SQL
        INSERT INTO CUSTOMER (
            CUST_ID, CUST_NAME, BALANCE, CREDIT_LIMIT
        ) VALUES (
            :WS-CUST-ID, :WS-CUST-NAME, 
            :WS-CUST-BALANCE, :WS-CUST-CREDIT-LIMIT
        )
    END-EXEC.
    
    IF SQLCODE = 0
        DISPLAY 'Customer inserted successfully'
    ELSE
        DISPLAY 'Insert failed: ' SQLCODE
    END-IF.

UPDATE-CUSTOMERS.
    EXEC SQL
        UPDATE CUSTOMER
        SET CREDIT_LIMIT = CREDIT_LIMIT * 1.1
        WHERE BALANCE > 5000
    END-EXEC.
    
    IF SQLCODE = 0
        MOVE SQLERRD(3) TO WS-UPDATE-COUNT
        DISPLAY 'Updated ' WS-UPDATE-COUNT ' customers'
    ELSE
        DISPLAY 'Update failed: ' SQLCODE
    END-IF.

DELETE-CUSTOMER.
    MOVE 10001 TO WS-CUST-ID.
    
    EXEC SQL
        DELETE FROM CUSTOMER
        WHERE CUST_ID = :WS-CUST-ID
    END-EXEC.
    
    IF SQLCODE = 0
        MOVE SQLERRD(3) TO WS-DELETE-COUNT
        DISPLAY 'Deleted ' WS-DELETE-COUNT ' customers'
    ELSE
        DISPLAY 'Delete failed: ' SQLCODE
    END-IF.

CONNECT-DB2.
    EXEC SQL
        CONNECT TO SAMPLEDB
    END-EXEC.
    IF SQLCODE = 0
        DISPLAY 'Connected to DB2'
    ELSE
        DISPLAY 'Connection failed'
        STOP RUN
    END-IF.

DISCONNECT-DB2.
    EXEC SQL
        CONNECT RESET
    END-EXEC.
    DISPLAY 'Disconnected from DB2'.

Common Pitfalls

  • Always check SQLCODE after SQL statements
  • Use host variables prefixed with colon (:) in SQL
  • Handle null indicators for nullable columns
  • Use cursors for multi-row result sets

SQL in COBOL Programs

Embedded SQL allows COBOL programs to execute SQL statements directly, providing seamless integration with relational databases.

SQL SELECT Operations

IDENTIFICATION DIVISION.
PROGRAM-ID. SQL-SELECT-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL
    INCLUDE SQLCA
END-EXEC.

*> Host variable definitions
EXEC SQL BEGIN DECLARE SECTION END-EXEC.
01 WS-EMPLOYEE-DATA.
   05 WS-EMP-ID PIC 9(5).
   05 WS-EMP-NAME PIC X(20).
   05 WS-EMP-SALARY PIC 9(6)V99.
   05 WS-EMP-DEPT PIC X(10).
   05 WS-EMP-HIRE-DATE PIC X(10).
EXEC SQL END DECLARE SECTION END-EXEC.

01 WS-DEPT-NAME PIC X(10) VALUE 'SALES'.
01 WS-MIN-SALARY PIC 9(6)V99 VALUE 40000.00.
01 WS-RECORD-COUNT PIC 9(4).
01 WS-EOF-FLAG PIC X VALUE 'N'.
   88 END-OF-DATA VALUE 'Y'.
PROCEDURE DIVISION.
MAIN-LOGIC.
    PERFORM CONNECT-DATABASE.
    PERFORM SINGLE-ROW-SELECT.
    PERFORM MULTI-ROW-SELECT.
    PERFORM PARAMETERIZED-SELECT.
    PERFORM DISCONNECT-DATABASE.
    STOP RUN.

SINGLE-ROW-SELECT.
    DISPLAY '=== SINGLE ROW SELECT ==='.
    MOVE 1001 TO WS-EMP-ID.
    
    EXEC SQL
        SELECT EMP_NAME, EMP_SALARY, EMP_DEPT
        INTO :WS-EMP-NAME, :WS-EMP-SALARY, :WS-EMP-DEPT
        FROM EMPLOYEE
        WHERE EMP_ID = :WS-EMP-ID
    END-EXEC.
    
    IF SQLCODE = 0
        DISPLAY 'Employee: ' WS-EMP-NAME
                ' Salary: ' WS-EMP-SALARY
                ' Dept: ' WS-EMP-DEPT
    ELSE
        DISPLAY 'Select failed: ' SQLCODE
    END-IF.

MULTI-ROW-SELECT.
    DISPLAY '=== MULTI-ROW SELECT WITH CURSOR ==='.
    EXEC SQL
        DECLARE EMP-CURSOR CURSOR FOR
        SELECT EMP_ID, EMP_NAME, EMP_SALARY
        FROM EMPLOYEE
        WHERE EMP_DEPT = :WS-DEPT-NAME
        ORDER BY EMP_SALARY DESC
    END-EXEC.
    
    EXEC SQL
        OPEN EMP-CURSOR
    END-EXEC.
    
    IF SQLCODE = 0
        MOVE 0 TO WS-RECORD-COUNT
        PERFORM UNTIL END-OF-DATA
            EXEC SQL
                FETCH EMP-CURSOR INTO
                    :WS-EMP-ID, :WS-EMP-NAME, :WS-EMP-SALARY
            END-EXEC
            
            EVALUATE SQLCODE
                WHEN 0
                    ADD 1 TO WS-RECORD-COUNT
                    DISPLAY WS-RECORD-COUNT ': ' 
                            WS-EMP-ID ' ' WS-EMP-NAME
                            ' $' WS-EMP-SALARY
                WHEN 100
                    SET END-OF-DATA TO TRUE
                WHEN OTHER
                    DISPLAY 'Fetch error: ' SQLCODE
                    SET END-OF-DATA TO TRUE
            END-EVALUATE
        END-PERFORM
        
        EXEC SQL
            CLOSE EMP-CURSOR
        END-EXEC
        
        DISPLAY 'Total records: ' WS-RECORD-COUNT
    ELSE
        DISPLAY 'Cursor open failed: ' SQLCODE
    END-IF.

PARAMETERIZED-SELECT.
    DISPLAY '=== PARAMETERIZED SELECT ==='.
    MOVE 'TECHNOLOGY' TO WS-DEPT-NAME.
    MOVE 50000.00 TO WS-MIN-SALARY.
    
    EXEC SQL
        SELECT COUNT(*)
        INTO :WS-RECORD-COUNT
        FROM EMPLOYEE
        WHERE EMP_DEPT = :WS-DEPT-NAME
          AND EMP_SALARY >= :WS-MIN-SALARY
    END-EXEC.
    
    IF SQLCODE = 0
        DISPLAY 'Employees in ' WS-DEPT-NAME 
                ' with salary >= ' WS-MIN-SALARY
                ': ' WS-RECORD-COUNT
    ELSE
        DISPLAY 'Count failed: ' SQLCODE
    END-IF.

CONNECT-DATABASE.
    EXEC SQL
        CONNECT TO COMPANYDB
    END-EXEC.
    IF SQLCODE = 0
        DISPLAY 'Connected to database'
    ELSE
        DISPLAY 'Connection failed'
        STOP RUN
    END-IF.

DISCONNECT-DATABASE.
    EXEC SQL
        CONNECT RESET
    END-EXEC.
    DISPLAY 'Disconnected from database'.

SQL Data Modification

IDENTIFICATION DIVISION.
PROGRAM-ID. SQL-DML-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL
    INCLUDE SQLCA
END-EXEC.

EXEC SQL BEGIN DECLARE SECTION END-EXEC.
01 WS-PRODUCT-DATA.
   05 WS-PROD-ID PIC 9(5).
   05 WS-PROD-NAME PIC X(30).
   05 WS-PROD-PRICE PIC 9(5)V99.
   05 WS-PROD-CATEGORY PIC X(15).
   05 WS-PROD-QUANTITY PIC 9(5).
EXEC SQL END DECLARE SECTION END-EXEC.

01 WS-AFFECTED-ROWS PIC S9(5).
01 WS-OLD-CATEGORY PIC X(15) VALUE 'OLD-STOCK'.
01 WS-NEW-CATEGORY PIC X(15) VALUE 'CLEARANCE'.
PROCEDURE DIVISION.
MAIN-LOGIC.
    PERFORM CONNECT-DB.
    PERFORM INSERT-PRODUCT.
    PERFORM UPDATE-PRODUCTS.
    PERFORM DELETE-PRODUCTS.
    PERFORM TRANSACTION-EXAMPLE.
    PERFORM DISCONNECT-DB.
    STOP RUN.

INSERT-PRODUCT.
    DISPLAY '=== INSERT PRODUCT ==='.
    MOVE 20001 TO WS-PROD-ID.
    MOVE 'LAPTOP COMPUTER' TO WS-PROD-NAME.
    MOVE 999.99 TO WS-PROD-PRICE.
    MOVE 'ELECTRONICS' TO WS-PROD-CATEGORY.
    MOVE 50 TO WS-PROD-QUANTITY.
    
    EXEC SQL
        INSERT INTO PRODUCT (
            PROD_ID, PROD_NAME, PRICE, CATEGORY, QUANTITY
        ) VALUES (
            :WS-PROD-ID, :WS-PROD-NAME, :WS-PROD-PRICE,
            :WS-PROD-CATEGORY, :WS-PROD-QUANTITY
        )
    END-EXEC.
    
    IF SQLCODE = 0
        DISPLAY 'Product inserted successfully'
    ELSE
        DISPLAY 'Insert failed: ' SQLCODE
    END-IF.

UPDATE-PRODUCTS.
    DISPLAY '=== UPDATE PRODUCTS ==='.
    MOVE 25.00 TO WS-PROD-PRICE.
    
    EXEC SQL
        UPDATE PRODUCT
        SET PRICE = PRICE - :WS-PROD-PRICE
        WHERE CATEGORY = :WS-OLD-CATEGORY
    END-EXEC.
    
    IF SQLCODE = 0
        MOVE SQLERRD(3) TO WS-AFFECTED-ROWS
        DISPLAY 'Updated ' WS-AFFECTED-ROWS ' products'
    ELSE
        DISPLAY 'Update failed: ' SQLCODE
    END-IF.

DELETE-PRODUCTS.
    DISPLAY '=== DELETE PRODUCTS ==='.
    MOVE 0 TO WS-PROD-QUANTITY.
    
    EXEC SQL
        DELETE FROM PRODUCT
        WHERE QUANTITY = :WS-PROD-QUANTITY
    END-EXEC.
    
    IF SQLCODE = 0
        MOVE SQLERRD(3) TO WS-AFFECTED-ROWS
        DISPLAY 'Deleted ' WS-AFFECTED-ROWS ' products'
    ELSE
        DISPLAY 'Delete failed: ' SQLCODE
    END-IF.

TRANSACTION-EXAMPLE.
    DISPLAY '=== TRANSACTION EXAMPLE ==='.
    EXEC SQL
        BEGIN WORK
    END-EXEC.
    
    *> Multiple operations in one transaction
    EXEC SQL
        UPDATE PRODUCT
        SET CATEGORY = :WS-NEW-CATEGORY
        WHERE CATEGORY = :WS-OLD-CATEGORY
    END-EXEC.
    
    IF SQLCODE = 0
        EXEC SQL
            COMMIT WORK
        END-EXEC
        DISPLAY 'Transaction committed'
    ELSE
        EXEC SQL
            ROLLBACK WORK
        END-EXEC
        DISPLAY 'Transaction rolled back'
    END-IF.

CONNECT-DB.
    EXEC SQL
        CONNECT TO INVENTORYDB
    END-EXEC.
    IF SQLCODE = 0
        DISPLAY 'Connected to database'
    ELSE
        DISPLAY 'Connection failed'
        STOP RUN
    END-IF.

DISCONNECT-DB.
    EXEC SQL
        CONNECT RESET
    END-EXEC.
    DISPLAY 'Disconnected from database'.

Common Pitfalls

  • Always declare host variables in DECLARE SECTION
  • Use COMMIT/ROLLBACK for transaction control
  • Handle SQLCODE 100 for "no data found" conditions
  • Use cursors for processing multiple rows

Advanced COBOL Features

Advanced COBOL features include dynamic programming, object-oriented extensions, and integration with modern technologies.

Dynamic SQL in COBOL

IDENTIFICATION DIVISION.
PROGRAM-ID. DYNAMIC-SQL-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL
    INCLUDE SQLCA
END-EXEC.

EXEC SQL BEGIN DECLARE SECTION END-EXEC.
01 WS-STMT-BUFFER PIC X(100).
01 WS-TABLE-NAME PIC X(20).
01 WS-COLUMN-NAME PIC X(20).
01 WS-WHERE-CLAUSE PIC X(50).
01 WS-EMP-ID PIC 9(5).
01 WS-EMP-NAME PIC X(20).
01 WS-EMP-SALARY PIC 9(6)V99.
EXEC SQL END DECLARE SECTION END-EXEC.

01 WS-PREPARE-STATUS PIC S9(9) COMP.
01 WS-DESCRIPTOR-AREA PIC X(100).
PROCEDURE DIVISION.
MAIN-LOGIC.
    PERFORM CONNECT-DB.
    PERFORM DYNAMIC-SELECT.
    PERFORM DYNAMIC-UPDATE.
    PERFORM DISCONNECT-DB.
    STOP RUN.

DYNAMIC-SELECT.
    DISPLAY '=== DYNAMIC SELECT ==='.
    MOVE 'EMPLOYEE' TO WS-TABLE-NAME.
    MOVE 'EMP_SALARY > 50000' TO WS-WHERE-CLAUSE.
    
    STRING 'SELECT EMP_ID, EMP_NAME, EMP_SALARY '
           'FROM ' WS-TABLE-NAME ' '
           'WHERE ' WS-WHERE-CLAUSE
        INTO WS-STMT-BUFFER.
    
    EXEC SQL
        PREPARE DYNAMIC-STMT FROM :WS-STMT-BUFFER
    END-EXEC.
    
    IF SQLCODE = 0
        EXEC SQL
            DECLARE DYNAMIC-CURSOR CURSOR FOR DYNAMIC-STMT
        END-EXEC.
        
        EXEC SQL
            OPEN DYNAMIC-CURSOR
        END-EXEC.
        
        IF SQLCODE = 0
            PERFORM UNTIL SQLCODE NOT = 0
                EXEC SQL
                    FETCH DYNAMIC-CURSOR INTO
                        :WS-EMP-ID, :WS-EMP-NAME, :WS-EMP-SALARY
                END-EXEC
                
                IF SQLCODE = 0
                    DISPLAY 'Dynamic result: ' WS-EMP-ID
                            ' ' WS-EMP-NAME ' ' WS-EMP-SALARY
                END-IF
            END-PERFORM
            
            EXEC SQL
                CLOSE DYNAMIC-CURSOR
            END-EXEC
        END-IF
    ELSE
        DISPLAY 'Prepare failed: ' SQLCODE
    END-IF.

DYNAMIC-UPDATE.
    DISPLAY '=== DYNAMIC UPDATE ==='.
    MOVE 'UPDATE EMPLOYEE SET EMP_SALARY = EMP_SALARY * 1.1 '
         'WHERE EMP_DEPT = ?'
        TO WS-STMT-BUFFER.
    
    EXEC SQL
        PREPARE UPDATE-STMT FROM :WS-STMT-BUFFER
    END-EXEC.
    
    IF SQLCODE = 0
        MOVE 'SALES' TO WS-COLUMN-NAME
        EXEC SQL
            EXECUTE UPDATE-STMT USING :WS-COLUMN-NAME
        END-EXEC
        
        IF SQLCODE = 0
            DISPLAY 'Dynamic update completed'
        ELSE
            DISPLAY 'Execute failed: ' SQLCODE
        END-IF
    ELSE
        DISPLAY 'Prepare failed: ' SQLCODE
    END-IF.

CONNECT-DB.
    EXEC SQL
        CONNECT TO SAMPLEDB
    END-EXEC.
    IF SQLCODE = 0
        DISPLAY 'Connected to database'
    ELSE
        DISPLAY 'Connection failed'
        STOP RUN
    END-IF.

DISCONNECT-DB.
    EXEC SQL
        CONNECT RESET
    END-EXEC.
    DISPLAY 'Disconnected from database'.

Object-Oriented COBOL

IDENTIFICATION DIVISION.
PROGRAM-ID. OO-COBOL-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
*> Factory object definition
01 BANK-ACCOUNT-FACTORY OBJECT REFERENCE.
01 ACCOUNT-OBJECT OBJECT REFERENCE.
01 INTEREST-OBJECT OBJECT REFERENCE.

*> Interface definitions
01 BANK-ACCOUNT PUBLIC.
   05 INTEREST-RATE PIC 9V999.
   05 BALANCE PIC 9(7)V99.
   
   METHOD-ID. DEPOSIT.
   PROCEDURE DIVISION USING AMOUNT PIC 9(5)V99
                   RETURNING NEW-BALANCE PIC 9(7)V99.
   END METHOD DEPOSIT.
   
   METHOD-ID. WITHDRAW.
   PROCEDURE DIVISION USING AMOUNT PIC 9(5)V99
                   RETURNING NEW-BALANCE PIC 9(7)V99.
   END METHOD WITHDRAW.
   
   METHOD-ID. GET-BALANCE.
   PROCEDURE DIVISION RETURNING CURRENT-BALANCE PIC 9(7)V99.
   END METHOD GET-BALANCE.

01 INTEREST-ACCOUNT INHERITS FROM BANK-ACCOUNT PUBLIC.
   METHOD-ID. CALCULATE-INTEREST.
   PROCEDURE DIVISION RETURNING INTEREST-AMOUNT PIC 9(5)V99.
   END METHOD CALCULATE-INTEREST.
   
   METHOD-ID. APPLY-INTEREST.
   PROCEDURE DIVISION.
   END METHOD APPLY-INTEREST.

PROCEDURE DIVISION.
MAIN-LOGIC.
    DISPLAY '=== OBJECT-ORIENTED COBOL DEMO ==='.
    
    PERFORM CREATE-OBJECTS.
    PERFORM USE-OBJECTS.
    PERFORM DESTROY-OBJECTS.
    
    STOP RUN.

CREATE-OBJECTS.
    *> Create factory and objects
    INVOKE BANK-ACCOUNT 'NEW' RETURNING BANK-ACCOUNT-FACTORY.
    
    INVOKE BANK-ACCOUNT-FACTORY 'CREATE' 
        RETURNING ACCOUNT-OBJECT.
    
    INVOKE INTEREST-ACCOUNT 'NEW' 
        RETURNING INTEREST-OBJECT.

USE-OBJECTS.
    *> Use account object
    INVOKE ACCOUNT-OBJECT 'DEPOSIT' 
        USING BY CONTENT 1000.00
        RETURNING WS-NEW-BALANCE.
    
    DISPLAY 'After deposit: ' WS-NEW-BALANCE.
    
    INVOKE ACCOUNT-OBJECT 'WITHDRAW' 
        USING BY CONTENT 250.00
        RETURNING WS-NEW-BALANCE.
    
    DISPLAY 'After withdrawal: ' WS-NEW-BALANCE.
    
    *> Use interest account object
    INVOKE INTEREST-OBJECT 'DEPOSIT' 
        USING BY CONTENT 5000.00.
    
    INVOKE INTEREST-OBJECT 'CALCULATE-INTEREST'
        RETURNING WS-INTEREST.
    
    DISPLAY 'Interest amount: ' WS-INTEREST.
    
    INVOKE INTEREST-OBJECT 'APPLY-INTEREST'.

DESTROY-OBJECTS.
    INVOKE ACCOUNT-OBJECT 'FINALIZE'.
    INVOKE INTEREST-OBJECT 'FINALIZE'.
    INVOKE BANK-ACCOUNT-FACTORY 'FINALIZE'.
    
    SET ACCOUNT-OBJECT TO NULL.
    SET INTEREST-OBJECT TO NULL.
    SET BANK-ACCOUNT-FACTORY TO NULL.
    
    DISPLAY 'Objects destroyed.'.

Web Services Integration

IDENTIFICATION DIVISION.
PROGRAM-ID. WEB-SERVICES-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SERVICE-URL PIC X(100) VALUE
   'http://api.example.com/customers'.
01 WS-REQUEST-BODY PIC X(500).
01 WS-RESPONSE-BODY PIC X(1000).
01 WS-HTTP-STATUS PIC 9(3).
01 WS-CUSTOMER-DATA.
   05 WS-CUST-ID PIC 9(5).
   05 WS-CUST-NAME PIC X(20).
   05 WS-CUST-EMAIL PIC X(30).

01 WS-JSON-BUFFER PIC X(500).
PROCEDURE DIVISION.
MAIN-LOGIC.
    DISPLAY '=== WEB SERVICES INTEGRATION ==='.
    
    PERFORM CALL-REST-SERVICE.
    PERFORM PARSE-JSON-RESPONSE.
    PERFORM UPDATE-DATABASE.
    
    STOP RUN.

CALL-REST-SERVICE.
    DISPLAY 'Calling REST web service...'.
    
    *> Prepare JSON request
    MOVE '{"customerId": 12345, "action": "getDetails"}'
        TO WS-REQUEST-BODY.
    
    *> Call web service (pseudo-code - actual implementation varies)
    CALL 'HTTP-POST' USING
        BY CONTENT WS-SERVICE-URL
        BY CONTENT WS-REQUEST-BODY
        BY REFERENCE WS-RESPONSE-BODY
        BY REFERENCE WS-HTTP-STATUS.
    
    IF WS-HTTP-STATUS = 200
        DISPLAY 'Service call successful'
        DISPLAY 'Response: ' WS-RESPONSE-BODY
    ELSE
        DISPLAY 'Service call failed: ' WS-HTTP-STATUS
    END-IF.

PARSE-JSON-RESPONSE.
    DISPLAY 'Parsing JSON response...'.
    
    *> Parse JSON response (simplified example)
    UNSTRING WS-RESPONSE-BODY
        DELIMITED BY '{"id":'
        INTO WS-JSON-BUFFER
        WS-CUST-ID
    END-UNSTRING.
    
    UNSTRING WS-RESPONSE-BODY
        DELIMITED BY '"name":"'
        INTO WS-JSON-BUFFER
        WS-CUST-NAME
    END-UNSTRING.
    
    UNSTRING WS-RESPONSE-BODY
        DELIMITED BY '"email":"'
        INTO WS-JSON-BUFFER
        WS-CUST-EMAIL
    END-UNSTRING.
    
    *> Remove trailing characters
    UNSTRING WS-CUST-NAME
        DELIMITED BY '"'
        INTO WS-CUST-NAME
    END-UNSTRING.
    
    UNSTRING WS-CUST-EMAIL
        DELIMITED BY '"'
        INTO WS-CUST-EMAIL
    END-UNSTRING.
    
    DISPLAY 'Parsed data - ID: ' WS-CUST-ID
            ' Name: ' WS-CUST-NAME
            ' Email: ' WS-CUST-EMAIL.

UPDATE-DATABASE.
    DISPLAY 'Updating database with web service data...'.
    
    *> Update local database with retrieved data
    EXEC SQL
        UPDATE CUSTOMER
        SET CUST_NAME = :WS-CUST-NAME,
            CUST_EMAIL = :WS-CUST-EMAIL
        WHERE CUST_ID = :WS-CUST-ID
    END-EXEC.
    
    IF SQLCODE = 0
        DISPLAY 'Database updated successfully'
    ELSE
        DISPLAY 'Database update failed: ' SQLCODE
    END-IF.

Common Pitfalls

  • Dynamic SQL requires careful SQL injection prevention
  • Object-oriented COBOL has limited compiler support
  • Web services integration often requires additional middleware
  • Test advanced features thoroughly in target environment

Group Items in COBOL

Group items allow you to organize related data fields into hierarchical structures. This is essential for working with records and complex data structures.

Basic Group Items

IDENTIFICATION DIVISION.
  PROGRAM-ID. GROUP-ITEMS-DEMO.
  DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-EMPLOYEE-RECORD.
     05 WS-EMP-INFO.
        10 WS-EMP-ID PIC 9(5) VALUE 12345.
        10 WS-EMP-NAME PIC X(20) VALUE 'John Smith'.
        10 WS-EMP-DEPT PIC X(10) VALUE 'SALES'.
     05 WS-EMP-SALARY-INFO.
        10 WS-BASE-SALARY PIC 9(5)V99 VALUE 50000.00.
        10 WS-BONUS PIC 9(5)V99 VALUE 5000.00.
        10 WS-TOTAL-SALARY PIC 9(6)V99.
  PROCEDURE DIVISION.
      COMPUTE WS-TOTAL-SALARY = 
          WS-BASE-SALARY + WS-BONUS.

      DISPLAY 'Employee Record: ' WS-EMPLOYEE-RECORD.
      DISPLAY 'Employee Name: ' WS-EMP-NAME.
      DISPLAY 'Total Salary: ' WS-TOTAL-SALARY.

      STOP RUN.

REDEFINES Clause

DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-DATE-FIELD PIC 9(8) VALUE 20240312.
  01 WS-DATE-BREAKDOWN REDEFINES WS-DATE-FIELD.
     05 WS-YEAR PIC 9(4).
     05 WS-MONTH PIC 9(2).
     05 WS-DAY PIC 9(2).

  01 WS-AMOUNT PIC 9(5)V99 VALUE 12345.67.
  01 WS-AMOUNT-BYTES REDEFINES WS-AMOUNT.
     05 WS-AMOUNT-INT PIC 9(5).
     05 WS-AMOUNT-DEC PIC 99.
  PROCEDURE DIVISION.
      DISPLAY 'Full date: ' WS-DATE-FIELD.
      DISPLAY 'Year: ' WS-YEAR.
      DISPLAY 'Month: ' WS-MONTH.
      DISPLAY 'Day: ' WS-DAY.

      DISPLAY 'Amount: ' WS-AMOUNT.
      DISPLAY 'Integer part: ' WS-AMOUNT-INT.
      DISPLAY 'Decimal part: ' WS-AMOUNT-DEC.

      STOP RUN.

OCCURS Clause for Arrays

DATA DIVISION.
  WORKING-STORAGE SECTION.
  01 WS-MONTH-NAMES.
     05 WS-MONTH PIC X(9) OCCURS 12 TIMES
        INDEXED BY MONTH-INDEX.

  01 WS-SALES-TABLE.
     05 WS-SALES-ENTRY OCCURS 10 TIMES
        INDEXED BY SALES-INDEX.
        10 WS-PRODUCT-ID PIC 9(5).
        10 WS-PRODUCT-NAME PIC X(20).
        10 WS-SALES-AMOUNT PIC 9(6)V99.
  PROCEDURE DIVISION.
      *> Initialize month names
      MOVE 'January' TO WS-MONTH(1).
      MOVE 'February' TO WS-MONTH(2).
      MOVE 'March' TO WS-MONTH(3).
      *> ... and so on for other months

      *> Display months
      PERFORM VARYING MONTH-INDEX FROM 1 BY 1
          UNTIL MONTH-INDEX > 3
          DISPLAY 'Month ' MONTH-INDEX ': ' 
                  WS-MONTH(MONTH-INDEX)
      END-PERFORM.

      STOP RUN.

Common Pitfalls

  • Group items share storage with redefined fields
  • OCCURS requires proper indexing or subscripting
  • INITIALIZE affects entire group items
  • Reference modification works on group items