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
-
Windows
Install GnuCOBOL (formerly OpenCOBOL) or Micro Focus Visual COBOL. For GnuCOBOL, download from the official website and add to your PATH. -
Linux
Use your distribution's package manager. For Ubuntu/Debian:sudo apt install gnucobol -
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
-
Create a file named
hello.cblwith the following content:IDENTIFICATION DIVISION. PROGRAM-ID. HELLO-WORLD. PROCEDURE DIVISION. DISPLAY 'Hello, World!'. STOP RUN. -
Compile the program:
cobc -x hello.cbl -
Run the executable:
./hello # On Linux hello.exe # On WindowsYou 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
DISPLAYfor 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
Table Searching in COBOL
COBOL provides powerful search capabilities for tables, including linear search (SEARCH) and binary search (SEARCH ALL) for efficient data retrieval.
Linear Search (SEARCH)
IDENTIFICATION DIVISION.
PROGRAM-ID. SEARCH-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CUSTOMER-TABLE.
05 WS-CUSTOMER OCCURS 10 TIMES
INDEXED BY CUST-INDEX.
10 WS-CUST-ID PIC 9(5).
10 WS-CUST-NAME PIC X(20).
10 WS-CUST-BALANCE PIC 9(5)V99.
01 WS-SEARCH-ID PIC 9(5) VALUE 12345.
01 WS-FOUND-NAME PIC X(20).
PROCEDURE DIVISION.
MAIN-LOGIC.
*> Initialize customer data
MOVE 11111 TO WS-CUST-ID(1).
MOVE 'Alice Brown' TO WS-CUST-NAME(1).
MOVE 1500.75 TO WS-CUST-BALANCE(1).
MOVE 12345 TO WS-CUST-ID(2).
MOVE 'Bob Green' TO WS-CUST-NAME(2).
MOVE 2300.50 TO WS-CUST-BALANCE(2).
MOVE 13579 TO WS-CUST-ID(3).
MOVE 'Carol White' TO WS-CUST-NAME(3).
MOVE 1800.25 TO WS-CUST-BALANCE(3).
*> Linear search
SET CUST-INDEX TO 1.
SEARCH WS-CUSTOMER
AT END
DISPLAY 'Customer not found'
WHEN WS-CUST-ID(CUST-INDEX) = WS-SEARCH-ID
MOVE WS-CUST-NAME(CUST-INDEX) TO WS-FOUND-NAME
DISPLAY 'Customer found: ' WS-FOUND-NAME
' Balance: ' WS-CUST-BALANCE(CUST-INDEX)
END-SEARCH.
STOP RUN.
Binary Search (SEARCH ALL)
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-EMPLOYEE-TABLE.
05 WS-EMPLOYEE OCCURS 100 TIMES
ASCENDING KEY IS WS-EMP-ID
INDEXED BY EMP-INDEX.
10 WS-EMP-ID PIC 9(5).
10 WS-EMP-NAME PIC X(20).
10 WS-EMP-DEPARTMENT PIC X(15).
01 WS-TARGET-EMP-ID PIC 9(5) VALUE 45678.
PROCEDURE DIVISION.
*> Note: Table must be sorted by WS-EMP-ID for SEARCH ALL
*> Initialize with sorted data
MOVE 12345 TO WS-EMP-ID(1).
MOVE 'John Adams' TO WS-EMP-NAME(1).
MOVE 'Engineering' TO WS-EMP-DEPARTMENT(1).
MOVE 23456 TO WS-EMP-ID(2).
MOVE 'Mary Brown' TO WS-EMP-NAME(2).
MOVE 'Marketing' TO WS-EMP-DEPARTMENT(2).
MOVE 45678 TO WS-EMP-ID(3).
MOVE 'Tom Clark' TO WS-EMP-NAME(3).
MOVE 'Sales' TO WS-EMP-DEPARTMENT(3).
*> Binary search - much faster for large tables
SEARCH ALL WS-EMPLOYEE
AT END DISPLAY 'Employee not found'
WHEN WS-EMP-ID(EMP-INDEX) = WS-TARGET-EMP-ID
DISPLAY 'Employee: ' WS-EMP-NAME(EMP-INDEX)
' Department: ' WS-EMP-DEPARTMENT(EMP-INDEX)
END-SEARCH.
STOP RUN.
Multiple Condition Search
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-ORDER-TABLE.
05 WS-ORDER OCCURS 50 TIMES
INDEXED BY ORDER-INDEX.
10 WS-ORDER-NUM PIC 9(6).
10 WS-CUSTOMER-CODE PIC 9(5).
10 WS-ORDER-STATUS PIC X.
88 STATUS-OPEN VALUE 'O'.
88 STATUS-CLOSED VALUE 'C'.
10 WS-ORDER-AMOUNT PIC 9(5)V99.
01 WS-TARGET-CUSTOMER PIC 9(5) VALUE 99999.
PROCEDURE DIVISION.
*> Search for open orders for specific customer
SET ORDER-INDEX TO 1.
SEARCH WS-ORDER
AT END DISPLAY 'No open orders found'
WHEN WS-CUSTOMER-CODE(ORDER-INDEX) = WS-TARGET-CUSTOMER
AND STATUS-OPEN(ORDER-INDEX)
DISPLAY 'Open Order: ' WS-ORDER-NUM(ORDER-INDEX)
' Amount: ' WS-ORDER-AMOUNT(ORDER-INDEX)
END-SEARCH.
STOP RUN.
Common Pitfalls
- SEARCH ALL requires sorted data with proper KEY definition
- Always initialize index before SEARCH
- Use AT END to handle not-found conditions
- Multiple conditions in WHEN clause use AND/OR operators
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