Chapter 32 Exercises: Embedded SQL for COBOL and C
Exercise 32.1: Host Variable Declarations
Objective: Practice mapping DB2 column types to COBOL host variables.
Given the following table definition:
CREATE TABLE MERIDIAN.LOAN_ACCOUNTS (
LOAN_NUM CHAR(12) NOT NULL,
CUST_ID INTEGER NOT NULL,
PRINCIPAL DECIMAL(15,2) NOT NULL,
INTEREST_RATE DECIMAL(5,4),
TERM_MONTHS SMALLINT NOT NULL,
PAYMENT_AMT DECIMAL(11,2),
NEXT_DUE_DATE DATE,
ORIGINATION_DT TIMESTAMP NOT NULL,
LOAN_STATUS CHAR(1) NOT NULL,
DESCRIPTION VARCHAR(200)
);
Tasks:
- Write the complete
EXEC SQL BEGIN DECLARE SECTION/EXEC SQL END DECLARE SECTIONblock with host variables for every column. - Include indicator variables for all nullable columns.
- Write the VARCHAR host variable using the correct level-49 structure.
Expected Output: A complete COBOL WORKING-STORAGE SECTION excerpt with all host variables and indicators properly declared.
Exercise 32.2: SELECT INTO with Error Handling
Objective: Write a single-row retrieval with comprehensive error handling.
Task: Write a COBOL paragraph that:
- Accepts a loan number in
HV-LOAN-NUM - Retrieves the principal, interest rate, and payment amount from
MERIDIAN.LOAN_ACCOUNTS - Handles all three possible outcomes: - SQLCODE = 0 (found) - SQLCODE = +100 (not found) - SQLCODE < 0 (error)
- Properly checks indicator variables for nullable columns before using the values
- Displays appropriate messages for each case
Exercise 32.3: Cursor Processing with Periodic Commits
Objective: Build a complete cursor-based processing loop with WITH HOLD and periodic commits.
Scenario: Write a COBOL program fragment that processes all overdue loans (where NEXT_DUE_DATE < CURRENT DATE and LOAN_STATUS = 'A'). For each overdue loan:
- Calculate a late fee of 2% of the payment amount
- Insert a record into
MERIDIAN.LATE_FEES(LOAN_NUM, FEE_DATE, FEE_AMOUNT) - Update the
LOAN_STATUSto 'D' (delinquent) - Commit every 500 rows
Requirements:
- Use a WITH HOLD cursor
- Use FOR UPDATE OF for the status column
- Use positioned UPDATE
- Handle errors gracefully — do not let one bad row stop the entire batch
Exercise 32.4: Multi-Row FETCH
Objective: Convert a single-row FETCH loop to a multi-row FETCH for better performance.
Given: A single-row fetch loop that processes 100,000 accounts:
EXEC SQL
DECLARE CSR-ACCTS CURSOR FOR
SELECT ACCOUNT_NUM, ACCT_NAME, BALANCE
FROM MERIDIAN.ACCOUNTS
WHERE BRANCH_ID = :HV-BRANCH-ID
ORDER BY ACCOUNT_NUM
END-EXEC.
Task:
1. Rewrite the cursor declaration for rowset positioning
2. Declare appropriate host variable arrays (rowset size of 100)
3. Write the FETCH loop using FETCH NEXT ROWSET ... FOR 100 ROWS
4. Write the inner loop that processes each row within the rowset
5. Handle the last rowset (which may have fewer than 100 rows)
Exercise 32.5: Static vs Dynamic SQL Decision
Objective: Analyze requirements and choose between static and dynamic SQL.
Scenario: Meridian Bank needs the following five SQL operations in a new COBOL program. For each, decide whether static SQL or dynamic SQL is more appropriate, and explain your reasoning:
- A SELECT that always queries
MERIDIAN.ACCOUNTSbyACCOUNT_NUM(primary key) - A query where the user specifies which columns to retrieve at runtime
- A nightly batch UPDATE that adds interest to all savings accounts
- A
CREATE INDEXstatement that runs during a maintenance window - A SELECT where the WHERE clause columns vary based on input parameters (sometimes filtering by branch, sometimes by status, sometimes by both)
Exercise 32.6: BIND Options Analysis
Objective: Choose appropriate BIND options for different scenarios.
Scenario: Recommend BIND options for each of the following programs at Meridian Bank:
-
Read-only reporting program that generates a snapshot report. It must see consistent data even if other programs are updating. It runs for 2 hours. - Recommended ISOLATION level? - CURRENTDATA setting? - RELEASE setting?
-
High-volume transaction posting program that updates millions of rows. It runs concurrently with online transactions. - Recommended ISOLATION level? - RELEASE setting? - ACQUIRE setting?
-
Ad-hoc query program where users type SQL at runtime. The program owner should control authorization, not the runtime user. - Static or dynamic SQL? - DYNAMICRULES setting?
Exercise 32.7: Error Recovery
Objective: Write robust error handling for deadlock and timeout scenarios.
Task: Write a COBOL paragraph called DEADLOCK-RETRY that:
- Is invoked when SQLCODE = -911 (deadlock, unit of work rolled back)
- Logs the error with the account number being processed
- Waits briefly (use a counter loop since COBOL has no SLEEP)
- Repositions the cursor to the last successfully committed point
- Retries up to 3 times before giving up
- If all retries fail, writes the account number to a reject file and continues
Hint: After a -911, the cursor is closed (the unit of work was rolled back). You need to re-OPEN the cursor and reposition it.
Exercise 32.8: Complete COBOL Program — Monthly Fee Assessment
Objective: Write a complete embedded SQL COBOL program from scratch.
Scenario: Meridian Bank assesses a monthly maintenance fee on checking accounts with balances below $1,500. Write a complete COBOL program (FEEASMT) that:
- Opens a cursor for all active checking accounts (
ACCT_TYPE = 'CHK') withBALANCE < 1500.00 - For each account:
- Deducts a $12.00 maintenance fee from the balance
- Inserts a transaction record into
MERIDIAN.TRANSACTIONSwithTXN_TYPE = 'FE'and description 'MONTHLY MAINTENANCE FEE' - If the balance would go negative, skip the fee and log the account number - Commits every 1,000 rows
- At the end, displays: - Total accounts assessed - Total fees collected - Total accounts skipped (insufficient balance)
- Sets the return code: 0 if no errors, 4 if some accounts were skipped, 16 if SQL errors occurred
Include: - Full IDENTIFICATION DIVISION, DATA DIVISION, and PROCEDURE DIVISION - SQLCA - Host variables and indicator variables - WITH HOLD cursor - Comprehensive error handling
Exercise 32.9: Embedded SQL in C
Objective: Translate a COBOL embedded SQL program to C.
Task: Take the account inquiry pattern from Section 32.10 and expand it into a complete C program that:
- Accepts an account number from command-line arguments
- Queries
MERIDIAN.ACCOUNTSfor the account details - Prints the account name, balance, and status
- If the account is found, queries
MERIDIAN.TRANSACTIONSfor the last 10 transactions using a cursor - Prints each transaction in a formatted table
- Handles all error conditions
Exercise 32.10: Precompile and Bind JCL
Objective: Write the complete JCL to precompile, compile, link-edit, and bind an embedded SQL COBOL program.
Task: Write a multi-step JCL job for the FEEASMT program from Exercise 32.8 that includes:
- Step 1 (PC): Precompile with
DSNHPC, producing a DBRM and modified COBOL source - Step 2 (COB): Compile the modified source with Enterprise COBOL
- Step 3 (LKED): Link-edit with the DB2 language interface module
- Step 4 (BIND): Bind the DBRM into a package in collection
MERIDIAN_BATCH - Step 5 (PLAN): Bind a plan referencing the collection
Include appropriate DSN names, DISP parameters, and condition codes for step execution control.