feat: add benchmark-programs — 58 telecom COBOL test programs

作为子目录纳入系统,与核心测试管道协同

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
NB-076
2026-06-25 09:53:21 +08:00
parent 50f9f0f52f
commit 94400d50d4
278 changed files with 44125 additions and 0 deletions
@@ -0,0 +1 @@
0000000000
@@ -0,0 +1,21 @@
# 23-select-condition — SELECT Condition Simulation
## 电信业务场景
客户合同检索。使用索引文件模拟SELECT条件检索,通过START+READ NEXT实现条件匹配和范围查询。
## Purpose
Simulates SQL SELECT with WHERE conditions using GnuCOBOL INDEXED files and START/READ NEXT operations.
## Test Coverage
1. **Single record by key** — READ with KEY IS (exact match WHERE)
2. **Range query** — START with NOT LESS THAN, loop with upper bound check
3. **Zero results** — Key not found, INVALID KEY handling
4. **Greater-than query** — START with GREATER THAN, read all following records
## Key Techniques
- INDEXED file ORGANIZATION with DYNAMIC access
- START for positioning (KEY IS GREATER THAN / NOT LESS THAN)
- READ NEXT for sequential traversal
- FILE STATUS checking
- INVALID KEY / NOT INVALID KEY for conditional handling
@@ -0,0 +1,22 @@
*** AUDIT START *** 2026/06/22 16:35:24
--- OPERATION SUMMARY ---
Program: Main23SelectCond Timestamp: 2026/06/22 16:35:24
Test cases: 043SelectCond Timestamp: 2026/06/22 16:35:24
Search type breakdown:
By-key : 01own:
Range : 01own:
Greater-than: 01own:
Batch control totals:
Requests: 04 Found: 00 NotFound: 01
Data integrity:
Hash total (balance): 000000000000
Performance metrics:
ByKey=02 Range=00 Greater=00
*** AUDIT END *** 2026/06/22 16:35:24
@@ -0,0 +1,754 @@
*> ============================================================
*> 23-select-condition : Customer Search (TELECOM BILLING)
*> Input : CUSTOMER-FILE (INDEXED)
*> Output: REPORT-FILE, TXN-LOG, AUDIT-FILE
*> Coverage: DB-N001, DB-N002, DB-N006, DB-R001
*> ============================================================
IDENTIFICATION DIVISION.
PROGRAM-ID. Main23SelectCond.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CUSTOMER-FILE ASSIGN TO "customer.dat"
ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS CUST-KEY
FILE STATUS IS CUST-STATUS.
SELECT REPORT-FILE ASSIGN TO "select-report.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS REPORT-STATUS.
SELECT TXN-LOG ASSIGN TO "txn-log.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS TXN-STATUS.
SELECT AUDIT-FILE ASSIGN TO "audit-file.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS AUDIT-STATUS.
DATA DIVISION.
FILE SECTION.
FD CUSTOMER-FILE.
01 CUST-RECORD.
05 CUST-KEY PIC X(10).
05 CUST-NAME PIC X(20).
05 CUST-BALANCE PIC 9(10).
FD REPORT-FILE.
01 REPORT-LINE PIC X(80).
FD TXN-LOG.
01 TXN-RECORD PIC X(120).
FD AUDIT-FILE.
01 AUDIT-RECORD PIC X(120).
WORKING-STORAGE SECTION.
01 WS-TELECOM-REC.
COPY "telecom/TEL-BILLING.cpy".
*> ---------- FILE STATUS flags ----------
01 CUST-STATUS PIC XX.
88 CUST-OK VALUE "00".
88 CUST-EOF VALUE "10".
88 CUST-NOTFOUND VALUE "23".
01 REPORT-STATUS PIC XX.
88 REPORT-OK VALUE "00".
01 TXN-STATUS PIC XX.
88 TXN-OK VALUE "00".
01 AUDIT-STATUS PIC XX.
88 AUDIT-OK VALUE "00".
*> ---------- Timestamp ----------
01 WS-DATE-SYS PIC 9(8).
01 WS-TIME-SYS PIC 9(8).
01 WS-TIMESTAMP-OUT PIC X(19).
01 WS-TS-DATE-FMT.
05 WS-TS-YEAR PIC X(4).
05 FILLER PIC X(1) VALUE "/".
05 WS-TS-MONTH PIC X(2).
05 FILLER PIC X(1) VALUE "/".
05 WS-TS-DAY PIC X(2).
01 WS-TS-TIME-FMT.
05 WS-TS-HOUR PIC X(2).
05 FILLER PIC X(1) VALUE ":".
05 WS-TS-MIN PIC X(2).
05 FILLER PIC X(1) VALUE ":".
05 WS-TS-SEC PIC X(2).
*> ---------- Error message ----------
01 WS-ERROR-MSG PIC X(60).
*> ---------- Existing query fields ----------
01 WS-CUST-COUNT PIC 9(02) VALUE 0.
01 WS-TEST-CASE PIC 9(02) VALUE 0.
01 WS-TOTAL-BALANCE PIC 9(10) VALUE 0.
01 WS-START-KEY PIC X(10).
01 WS-END-KEY PIC X(10).
01 WS-RANGE-LOW PIC X(10).
01 WS-RANGE-HIGH PIC X(10).
01 WS-HEADER1.
05 FILLER PIC X(20) VALUE "KEY NAME".
05 FILLER PIC X(20) VALUE " BALANCE".
01 WS-DETAIL-LINE.
05 DL-KEY PIC X(10).
05 FILLER PIC X(02) VALUE SPACES.
05 DL-NAME PIC X(20).
05 FILLER PIC X(02) VALUE SPACES.
05 DL-BALANCE PIC Z(9)9.
*> ---------- Test data ----------
01 CUST-DATA-AREA.
05 CUST-DATA OCCURS 6 TIMES.
10 CD-KEY PIC X(10).
10 CD-NAME PIC X(20).
10 CD-BALANCE PIC 9(10).
01 CUST-DATA-VALUES.
05 PIC X(40) VALUE "CUST000001ZHANG-SAN 0000001000".
05 PIC X(40) VALUE "CUST000002LI-SI 0000002000".
05 PIC X(40) VALUE "CUST000003WANG-WU 0000003000".
05 PIC X(40) VALUE "CUST000004ZHAO-QIAN 0000004000".
05 PIC X(40) VALUE "CUST000005SUN-LI 0000005000".
05 PIC X(40) VALUE "CUST000010ZHOU-WU 0000010000".
01 CUST-DATA-REDEF REDEFINES CUST-DATA-VALUES.
05 CUST-DATA-ENTRY OCCURS 6 TIMES.
10 CDE-KEY PIC X(10).
10 CDE-NAME PIC X(20).
10 CDE-BALANCE PIC 9(10).
01 IDX PIC 9(02).
*> ===== NEW FIELDS =====
*> Operation type statistics
01 WS-OP-BY-KEY-COUNT PIC 9(02) VALUE 0.
01 WS-OP-RANGE-COUNT PIC 9(02) VALUE 0.
01 WS-OP-GREATER-COUNT PIC 9(02) VALUE 0.
01 WS-FOUND-BY-KEY PIC 9(02) VALUE 0.
01 WS-FOUND-RANGE PIC 9(02) VALUE 0.
01 WS-FOUND-GREATER PIC 9(02) VALUE 0.
*> Search performance metrics
01 WS-PERF-READS PIC 9(02) VALUE 0.
01 WS-PERF-START-READS PIC 9(02) VALUE 0.
01 WS-PERF-RANGE-READS PIC 9(02) VALUE 0.
01 WS-PERF-GREATER-READS PIC 9(02) VALUE 0.
*> Hash total for data integrity
01 WS-HASH-TOTAL PIC 9(12) VALUE 0.
*> Batch control totals
01 WS-BC-TOTAL-REQUESTS PIC 9(02) VALUE 0.
01 WS-BC-TOTAL-FOUND PIC 9(02) VALUE 0.
01 WS-BC-TOTAL-NOTFOUND PIC 9(02) VALUE 0.
*> Key validation flag
01 WS-KEY-VALID-FLAG PIC X(01).
88 WS-KEY-VALID-YES VALUE "Y".
88 WS-KEY-VALID-NO VALUE "N".
*> Transaction log work area
01 WS-TXN-BUFFER PIC X(120).
01 WS-TXN-TYPE PIC X(15).
01 WS-TXN-DETAIL PIC X(88).
PROCEDURE DIVISION.
MAIN-PROCEDURE.
PERFORM 1000-INIT THRU 1000-EXIT
PERFORM 2000-OPEN-FILES THRU 2000-EXIT
PERFORM 3000-READ-INPUT THRU 3000-EXIT
PERFORM 4000-REPORT THRU 4000-EXIT
PERFORM 5000-AUDIT THRU 5000-EXIT
PERFORM 9000-EXIT-PGM THRU 9000-EXIT
STOP RUN.
*> ============================================================
*> 1000-INIT : Create INDEXED file, populate with test data
*> ============================================================
1000-INIT SECTION.
1000-START.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] 1000-INIT: Starting".
OPEN OUTPUT CUSTOMER-FILE.
IF NOT CUST-OK
MOVE "1000: OPEN OUTPUT CUST FAILED" TO WS-ERROR-MSG
PERFORM 6000-ERROR-HANDLE THRU 6000-EXIT
END-IF.
CLOSE CUSTOMER-FILE.
IF NOT CUST-OK
MOVE "1000: CLOSE CUST (post-OUTPUT) FAILED"
TO WS-ERROR-MSG
PERFORM 6000-ERROR-HANDLE THRU 6000-EXIT
END-IF.
OPEN I-O CUSTOMER-FILE.
IF NOT CUST-OK
MOVE "1000: OPEN I-O CUST FAILED" TO WS-ERROR-MSG
PERFORM 6000-ERROR-HANDLE THRU 6000-EXIT
END-IF.
PERFORM VARYING IDX FROM 1 BY 1 UNTIL IDX > 6
MOVE CDE-KEY(IDX) TO CUST-KEY
MOVE CDE-NAME(IDX) TO CUST-NAME
MOVE CDE-BALANCE(IDX) TO CUST-BALANCE
WRITE CUST-RECORD
INVALID KEY
DISPLAY "[" WS-TIMESTAMP-OUT "]"
" INIT INSERT FAILED: " CUST-STATUS
END-WRITE
IF NOT CUST-OK
DISPLAY "[" WS-TIMESTAMP-OUT "] INIT WRITE FAILED"
" KEY=" CUST-KEY " STATUS=" CUST-STATUS
END-IF
END-PERFORM.
CLOSE CUSTOMER-FILE.
IF NOT CUST-OK
MOVE "1000: CLOSE CUST (post-WRITE) FAILED"
TO WS-ERROR-MSG
PERFORM 6000-ERROR-HANDLE THRU 6000-EXIT
END-IF.
OPEN I-O CUSTOMER-FILE.
IF NOT CUST-OK
MOVE "1000: OPEN I-O (reopen) FAILED" TO WS-ERROR-MSG
PERFORM 6000-ERROR-HANDLE THRU 6000-EXIT
END-IF.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] 1000-INIT: Complete".
GO TO 1000-EXIT.
1000-EXIT.
EXIT.
*> ============================================================
*> 2000-OPEN-FILES : Open output files, write audit header
*> ============================================================
2000-OPEN-FILES SECTION.
2000-START.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] 2000-OPEN-FILES:"
" Opening output files".
OPEN OUTPUT REPORT-FILE.
IF NOT REPORT-OK
MOVE "2000: OPEN REPORT FAILED" TO WS-ERROR-MSG
PERFORM 6000-ERROR-HANDLE THRU 6000-EXIT
END-IF.
OPEN OUTPUT TXN-LOG.
IF NOT TXN-OK
MOVE "2000: OPEN TXN-LOG FAILED" TO WS-ERROR-MSG
PERFORM 6000-ERROR-HANDLE THRU 6000-EXIT
END-IF.
OPEN OUTPUT AUDIT-FILE.
IF NOT AUDIT-OK
MOVE "2000: OPEN AUDIT FAILED" TO WS-ERROR-MSG
PERFORM 6000-ERROR-HANDLE THRU 6000-EXIT
END-IF.
PERFORM GET-TIMESTAMP.
WRITE AUDIT-RECORD FROM SPACES.
STRING "*** AUDIT START *** " WS-TIMESTAMP-OUT
INTO AUDIT-RECORD
END-STRING.
WRITE AUDIT-RECORD.
IF NOT AUDIT-OK
DISPLAY "[" WS-TIMESTAMP-OUT "] AUDIT HEADER WRITE"
" FAILED STATUS=" AUDIT-STATUS
END-IF.
DISPLAY "[" WS-TIMESTAMP-OUT "] 2000: All files opened".
GO TO 2000-EXIT.
2000-EXIT.
EXIT.
*> ============================================================
*> 3000-READ-INPUT : Execute 4 test cases (by-key, range,
*> zero-results, greater-than). Each includes key validation,
*> search execution, statistics update, and TXN log entry.
*> ============================================================
3000-READ-INPUT SECTION.
3000-START.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] 3000-READ-INPUT:"
" Starting test cases".
*> Report header
MOVE WS-HEADER1 TO REPORT-LINE.
WRITE REPORT-LINE.
IF NOT REPORT-OK
DISPLAY "[" WS-TIMESTAMP-OUT "] REPORT HEADER WRITE"
" FAILED STATUS=" REPORT-STATUS
END-IF.
*> === TEST 1 : WHERE key = 'CUST000003' ===
ADD 1 TO WS-TEST-CASE.
ADD 1 TO WS-BC-TOTAL-REQUESTS.
MOVE 0 TO WS-PERF-READS.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] === Test " WS-TEST-CASE
": WHERE key = 'CUST000003' ===".
MOVE "CUST000003" TO WS-START-KEY.
MOVE WS-START-KEY TO CUST-KEY.
PERFORM 3100-VALIDATE-KEY THRU 3100-EXIT.
PERFORM 3200-SELECT-BY-KEY.
ADD WS-CUST-COUNT TO WS-BC-TOTAL-FOUND.
ADD 1 TO WS-OP-BY-KEY-COUNT.
ADD WS-PERF-READS TO WS-PERF-START-READS.
MOVE "BY-KEY" TO WS-TXN-TYPE.
STRING "KEY=" WS-START-KEY " FOUND=" WS-CUST-COUNT
INTO WS-TXN-DETAIL
END-STRING.
PERFORM 5000-TXN-LOG.
*> === TEST 2 : key >= 'CUST000002' AND <= 'CUST000005' ===
ADD 1 TO WS-TEST-CASE.
ADD 1 TO WS-BC-TOTAL-REQUESTS.
MOVE 0 TO WS-PERF-READS.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] === Test " WS-TEST-CASE
": WHERE key >= 'CUST000002'"
" AND key <= 'CUST000005' ===".
MOVE "CUST000002" TO WS-RANGE-LOW.
MOVE "CUST000005" TO WS-RANGE-HIGH.
MOVE WS-RANGE-LOW TO CUST-KEY.
PERFORM 3100-VALIDATE-KEY THRU 3100-EXIT.
MOVE WS-RANGE-HIGH TO CUST-KEY.
PERFORM 3100-VALIDATE-KEY THRU 3100-EXIT.
PERFORM 3200-SELECT-RANGE.
ADD WS-CUST-COUNT TO WS-BC-TOTAL-FOUND.
ADD 1 TO WS-OP-RANGE-COUNT.
ADD WS-PERF-READS TO WS-PERF-RANGE-READS.
MOVE "RANGE" TO WS-TXN-TYPE.
STRING "LOW=" WS-RANGE-LOW " HIGH=" WS-RANGE-HIGH
" FOUND=" WS-CUST-COUNT
INTO WS-TXN-DETAIL
END-STRING.
PERFORM 5000-TXN-LOG.
*> === TEST 3 : WHERE none match (key = 'ZZZZZZZZZZ') ===
ADD 1 TO WS-TEST-CASE.
ADD 1 TO WS-BC-TOTAL-REQUESTS.
MOVE 0 TO WS-PERF-READS.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] === Test " WS-TEST-CASE
": WHERE none match ===".
MOVE "ZZZZZZZZZZ" TO WS-START-KEY.
MOVE WS-START-KEY TO CUST-KEY.
PERFORM 3100-VALIDATE-KEY THRU 3100-EXIT.
PERFORM 3200-SELECT-BY-KEY.
ADD WS-CUST-COUNT TO WS-BC-TOTAL-FOUND.
IF WS-CUST-COUNT = 0
ADD 1 TO WS-BC-TOTAL-NOTFOUND
END-IF.
ADD WS-PERF-READS TO WS-PERF-START-READS.
MOVE "BY-KEY" TO WS-TXN-TYPE.
STRING "KEY=" WS-START-KEY " FOUND=" WS-CUST-COUNT
INTO WS-TXN-DETAIL
END-STRING.
PERFORM 5000-TXN-LOG.
*> === TEST 4 : WHERE key > 'CUST000003' ===
ADD 1 TO WS-TEST-CASE.
ADD 1 TO WS-BC-TOTAL-REQUESTS.
MOVE 0 TO WS-PERF-READS.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] === Test " WS-TEST-CASE
": WHERE key > 'CUST000003' ===".
MOVE "CUST000003" TO WS-START-KEY.
MOVE WS-START-KEY TO CUST-KEY.
PERFORM 3100-VALIDATE-KEY THRU 3100-EXIT.
PERFORM 3200-SELECT-GREATER-THAN.
ADD WS-CUST-COUNT TO WS-BC-TOTAL-FOUND.
ADD 1 TO WS-OP-GREATER-COUNT.
ADD WS-PERF-READS TO WS-PERF-GREATER-READS.
MOVE "GREATER-THAN" TO WS-TXN-TYPE.
STRING "KEY>" WS-START-KEY " FOUND=" WS-CUST-COUNT
INTO WS-TXN-DETAIL
END-STRING.
PERFORM 5000-TXN-LOG.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] 3000: All test cases done".
GO TO 3000-EXIT.
3000-EXIT.
EXIT.
*> ============================================================
*> 3100-VALIDATE-KEY : Validate key format "CUST" + 6 digits.
*> Sets WS-KEY-VALID-FLAG to "Y"/"N".
*> ============================================================
3100-VALIDATE-KEY SECTION.
3100-START.
MOVE "Y" TO WS-KEY-VALID-FLAG.
IF CUST-KEY(1:4) NOT = "CUST"
MOVE "N" TO WS-KEY-VALID-FLAG
DISPLAY "[" WS-TIMESTAMP-OUT "] VALIDATE: key ["
CUST-KEY "] prefix not 'CUST'"
END-IF.
*> Check that positions 5-10 are all numeric digits
PERFORM VARYING IDX FROM 5 BY 1 UNTIL IDX > 10
IF CUST-KEY(IDX:1) < "0" OR CUST-KEY(IDX:1) > "9"
MOVE "N" TO WS-KEY-VALID-FLAG
END-IF
END-PERFORM.
IF WS-KEY-VALID-NO
DISPLAY "[" WS-TIMESTAMP-OUT "] VALIDATE: key ["
CUST-KEY "] INVALID FORMAT"
END-IF.
GO TO 3100-EXIT.
3100-EXIT.
EXIT.
*> ============================================================
*> 3200-PROCESS-RECORD : Populate detail line, accumulate hash
*> total, display result, and write to report.
*> ============================================================
3200-PROCESS-RECORD SECTION.
3200-START.
MOVE CUST-KEY TO DL-KEY.
MOVE CUST-NAME TO DL-NAME.
MOVE CUST-BALANCE TO DL-BALANCE.
ADD CUST-BALANCE TO WS-HASH-TOTAL.
DISPLAY " " WS-DETAIL-LINE.
PERFORM 3300-WRITE-OUTPUT THRU 3300-EXIT.
GO TO 3200-EXIT.
3200-EXIT.
EXIT.
*> ---- Single-record read by primary key ----
3200-SELECT-BY-KEY.
MOVE 0 TO WS-CUST-COUNT.
MOVE WS-START-KEY TO CUST-KEY.
READ CUSTOMER-FILE KEY IS CUST-KEY
INVALID KEY
PERFORM GET-TIMESTAMP
DISPLAY "[" WS-TIMESTAMP-OUT "] KEY NOT FOUND: "
WS-START-KEY
DISPLAY "[" WS-TIMESTAMP-OUT "] ROW EXISTENCE"
" CHECK: no record for key "
WS-START-KEY " STATUS=" CUST-STATUS
MOVE " KEY NOT FOUND" TO REPORT-LINE
WRITE REPORT-LINE
IF NOT REPORT-OK
DISPLAY "[" WS-TIMESTAMP-OUT "] REPORT WRITE"
" FAILED STATUS=" REPORT-STATUS
END-IF
NOT INVALID KEY
ADD 1 TO WS-CUST-COUNT
PERFORM 3200-PROCESS-RECORD THRU 3200-EXIT
END-READ.
IF NOT CUST-OK AND NOT CUST-NOTFOUND
DISPLAY "[" WS-TIMESTAMP-OUT "] READ FAILED"
" STATUS=" CUST-STATUS
END-IF.
ADD 1 TO WS-PERF-READS.
*> ---- Range search via START / READ NEXT ----
3200-SELECT-RANGE.
MOVE 0 TO WS-CUST-COUNT.
MOVE WS-RANGE-LOW TO CUST-KEY.
START CUSTOMER-FILE KEY IS NOT LESS THAN CUST-KEY
IF CUST-STATUS NOT = "00"
DISPLAY "[" WS-TIMESTAMP-OUT "] RANGE START"
" FAILED STATUS=" CUST-STATUS
MOVE " RANGE START FAILED" TO REPORT-LINE
WRITE REPORT-LINE
ELSE
PERFORM UNTIL CUST-EOF
READ CUSTOMER-FILE NEXT RECORD
AT END
SET CUST-EOF TO TRUE
NOT AT END
IF CUST-KEY > WS-RANGE-HIGH
SET CUST-EOF TO TRUE
ELSE
ADD 1 TO WS-CUST-COUNT
PERFORM 3200-PROCESS-RECORD
THRU 3200-EXIT
END-IF
END-READ
IF CUST-OK
ADD 1 TO WS-PERF-READS
END-IF
END-PERFORM
END-IF.
*> ---- Greater-than search via START / READ NEXT ----
3200-SELECT-GREATER-THAN.
MOVE 0 TO WS-CUST-COUNT.
MOVE WS-START-KEY TO CUST-KEY.
START CUSTOMER-FILE KEY IS GREATER THAN CUST-KEY
IF CUST-STATUS NOT = "00"
DISPLAY "[" WS-TIMESTAMP-OUT "] GREATER START"
" FAILED STATUS=" CUST-STATUS
ELSE
PERFORM UNTIL CUST-EOF
READ CUSTOMER-FILE NEXT RECORD
AT END
SET CUST-EOF TO TRUE
NOT AT END
ADD 1 TO WS-CUST-COUNT
PERFORM 3200-PROCESS-RECORD
THRU 3200-EXIT
END-READ
IF CUST-OK
ADD 1 TO WS-PERF-READS
END-IF
END-PERFORM
END-IF.
*> ============================================================
*> 3300-WRITE-OUTPUT : Write a single detail line to report
*> ============================================================
3300-WRITE-OUTPUT SECTION.
3300-START.
MOVE WS-DETAIL-LINE TO REPORT-LINE.
WRITE REPORT-LINE.
IF NOT REPORT-OK
MOVE "3300: WRITE REPORT FAILED" TO WS-ERROR-MSG
DISPLAY "[" WS-TIMESTAMP-OUT "] " WS-ERROR-MSG
" STATUS=" REPORT-STATUS
PERFORM 6000-ERROR-HANDLE THRU 6000-EXIT
END-IF.
GO TO 3300-EXIT.
3300-EXIT.
EXIT.
*> ============================================================
*> 4000-REPORT : Summary with batch totals, operation stats,
*> hash totals, and performance metrics
*> ============================================================
4000-REPORT SECTION.
4000-START.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] 4000-REPORT:"
" Generating summary".
WRITE REPORT-LINE FROM SPACES.
MOVE "=== BATCH CONTROL TOTALS ===" TO REPORT-LINE.
WRITE REPORT-LINE.
STRING "Total search requests : " WS-BC-TOTAL-REQUESTS
INTO REPORT-LINE
END-STRING.
WRITE REPORT-LINE.
STRING "Total records found : " WS-BC-TOTAL-FOUND
INTO REPORT-LINE
END-STRING.
WRITE REPORT-LINE.
STRING "Total records not found: " WS-BC-TOTAL-NOTFOUND
INTO REPORT-LINE
END-STRING.
WRITE REPORT-LINE.
WRITE REPORT-LINE FROM SPACES.
MOVE "=== OPERATION TYPE STATISTICS ===" TO REPORT-LINE.
WRITE REPORT-LINE.
STRING "By-key searches : " WS-OP-BY-KEY-COUNT
INTO REPORT-LINE
END-STRING.
WRITE REPORT-LINE.
STRING "Range searches : " WS-OP-RANGE-COUNT
INTO REPORT-LINE
END-STRING.
WRITE REPORT-LINE.
STRING "Greater searches : " WS-OP-GREATER-COUNT
INTO REPORT-LINE
END-STRING.
WRITE REPORT-LINE.
WRITE REPORT-LINE FROM SPACES.
MOVE "=== DATA INTEGRITY HASH TOTALS ===" TO REPORT-LINE.
WRITE REPORT-LINE.
STRING "Hash total (CUST-BALANCE sum): " WS-HASH-TOTAL
INTO REPORT-LINE
END-STRING.
WRITE REPORT-LINE.
WRITE REPORT-LINE FROM SPACES.
MOVE "=== SEARCH PERFORMANCE METRICS ===" TO REPORT-LINE.
WRITE REPORT-LINE.
STRING "Total READs (by-key) : " WS-PERF-START-READS
INTO REPORT-LINE
END-STRING.
WRITE REPORT-LINE.
STRING "Total READs (range) : " WS-PERF-RANGE-READS
INTO REPORT-LINE
END-STRING.
WRITE REPORT-LINE.
STRING "Total READs (greater-than): " WS-PERF-GREATER-READS
INTO REPORT-LINE
END-STRING.
WRITE REPORT-LINE.
DISPLAY "[" WS-TIMESTAMP-OUT "] 4000: Report written".
GO TO 4000-EXIT.
4000-EXIT.
EXIT.
*> ============================================================
*> 5000-AUDIT : Write operation summary to audit file with
*> timestamps, statistics, hash totals, and performance data
*> ============================================================
5000-AUDIT SECTION.
5000-START.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] 5000-AUDIT:"
" Writing audit records".
WRITE AUDIT-RECORD FROM SPACES.
MOVE "--- OPERATION SUMMARY ---" TO AUDIT-RECORD.
WRITE AUDIT-RECORD.
STRING " Program: Main23SelectCond Timestamp: "
WS-TIMESTAMP-OUT
INTO AUDIT-RECORD
END-STRING.
WRITE AUDIT-RECORD.
STRING " Test cases: " WS-TEST-CASE
INTO AUDIT-RECORD
END-STRING.
WRITE AUDIT-RECORD.
WRITE AUDIT-RECORD FROM SPACES.
MOVE " Search type breakdown:" TO AUDIT-RECORD.
WRITE AUDIT-RECORD.
STRING " By-key : " WS-OP-BY-KEY-COUNT
INTO AUDIT-RECORD
END-STRING.
WRITE AUDIT-RECORD.
STRING " Range : " WS-OP-RANGE-COUNT
INTO AUDIT-RECORD
END-STRING.
WRITE AUDIT-RECORD.
STRING " Greater-than: " WS-OP-GREATER-COUNT
INTO AUDIT-RECORD
END-STRING.
WRITE AUDIT-RECORD.
WRITE AUDIT-RECORD FROM SPACES.
MOVE " Batch control totals:" TO AUDIT-RECORD.
WRITE AUDIT-RECORD.
STRING " Requests: " WS-BC-TOTAL-REQUESTS
" Found: " WS-BC-TOTAL-FOUND
" NotFound: " WS-BC-TOTAL-NOTFOUND
INTO AUDIT-RECORD
END-STRING.
WRITE AUDIT-RECORD.
WRITE AUDIT-RECORD FROM SPACES.
MOVE " Data integrity:" TO AUDIT-RECORD.
WRITE AUDIT-RECORD.
STRING " Hash total (balance): " WS-HASH-TOTAL
INTO AUDIT-RECORD
END-STRING.
WRITE AUDIT-RECORD.
WRITE AUDIT-RECORD FROM SPACES.
MOVE " Performance metrics:" TO AUDIT-RECORD.
WRITE AUDIT-RECORD.
STRING " ByKey=" WS-PERF-START-READS
" Range=" WS-PERF-RANGE-READS
" Greater=" WS-PERF-GREATER-READS
INTO AUDIT-RECORD
END-STRING.
WRITE AUDIT-RECORD.
WRITE AUDIT-RECORD FROM SPACES.
PERFORM GET-TIMESTAMP.
STRING "*** AUDIT END *** " WS-TIMESTAMP-OUT
INTO AUDIT-RECORD
END-STRING.
WRITE AUDIT-RECORD.
IF NOT AUDIT-OK
DISPLAY "[" WS-TIMESTAMP-OUT "] AUDIT END WRITE"
" FAILED STATUS=" AUDIT-STATUS
END-IF.
DISPLAY "[" WS-TIMESTAMP-OUT "] 5000: Audit written".
GO TO 5000-EXIT.
5000-EXIT.
EXIT.
*> ---- Transaction log entry ----
5000-TXN-LOG.
PERFORM GET-TIMESTAMP.
STRING WS-TXN-TYPE " | " WS-TXN-DETAIL
" | " WS-TIMESTAMP-OUT
INTO WS-TXN-BUFFER
END-STRING.
MOVE WS-TXN-BUFFER TO TXN-RECORD.
WRITE TXN-RECORD.
IF NOT TXN-OK
DISPLAY "[" WS-TIMESTAMP-OUT "] TXN LOG WRITE"
" FAILED STATUS=" TXN-STATUS
END-IF.
*> ============================================================
*> 6000-ERROR-HANDLE : Log errors to DISPLAY, audit, report,
*> and transaction log
*> ============================================================
6000-ERROR-HANDLE SECTION.
6000-START.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] 6000-ERROR: " WS-ERROR-MSG.
STRING "ERROR: " WS-ERROR-MSG " at " WS-TIMESTAMP-OUT
INTO AUDIT-RECORD
END-STRING.
WRITE AUDIT-RECORD.
STRING "ERROR: " WS-ERROR-MSG " at " WS-TIMESTAMP-OUT
INTO REPORT-LINE
END-STRING.
WRITE REPORT-LINE.
MOVE "ERROR" TO WS-TXN-TYPE.
MOVE WS-ERROR-MSG TO WS-TXN-DETAIL.
PERFORM 5000-TXN-LOG.
GO TO 6000-EXIT.
6000-EXIT.
EXIT.
*> ============================================================
*> 9000-EXIT-PGM : Close all files, display final summary
*> ============================================================
9000-EXIT-PGM SECTION.
9000-START.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] 9000-EXIT: Closing files".
CLOSE REPORT-FILE.
IF NOT REPORT-OK
DISPLAY "[" WS-TIMESTAMP-OUT "] CLOSE REPORT-FILE"
" FAILED STATUS=" REPORT-STATUS
END-IF.
CLOSE CUSTOMER-FILE.
IF NOT CUST-OK
DISPLAY "[" WS-TIMESTAMP-OUT "] CLOSE CUSTOMER-FILE"
" FAILED STATUS=" CUST-STATUS
END-IF.
CLOSE TXN-LOG.
IF NOT TXN-OK
DISPLAY "[" WS-TIMESTAMP-OUT "] CLOSE TXN-LOG"
" FAILED STATUS=" TXN-STATUS
END-IF.
CLOSE AUDIT-FILE.
IF NOT AUDIT-OK
DISPLAY "[" WS-TIMESTAMP-OUT "] CLOSE AUDIT-FILE"
" FAILED STATUS=" AUDIT-STATUS
END-IF.
PERFORM GET-TIMESTAMP.
DISPLAY "[" WS-TIMESTAMP-OUT "] ====== Finished =====".
DISPLAY "[" WS-TIMESTAMP-OUT "] Requests:"
WS-BC-TOTAL-REQUESTS " Found:" WS-BC-TOTAL-FOUND
" NotFound:" WS-BC-TOTAL-NOTFOUND.
DISPLAY "[" WS-TIMESTAMP-OUT "] Hash total:" WS-HASH-TOTAL.
DISPLAY "[" WS-TIMESTAMP-OUT "] Reads ByKey:"
WS-PERF-START-READS " Range:" WS-PERF-RANGE-READS
" Greater:" WS-PERF-GREATER-READS.
GO TO 9000-EXIT.
9000-EXIT.
EXIT.
*> ============================================================
*> GET-TIMESTAMP : Build WS-TIMESTAMP-OUT = YYYY/MM/DD HH:MM:SS
*> ============================================================
GET-TIMESTAMP.
ACCEPT WS-DATE-SYS FROM DATE YYYYMMDD.
ACCEPT WS-TIME-SYS FROM TIME.
MOVE WS-DATE-SYS(1:4) TO WS-TS-YEAR.
MOVE WS-DATE-SYS(5:2) TO WS-TS-MONTH.
MOVE WS-DATE-SYS(7:2) TO WS-TS-DAY.
MOVE WS-TIME-SYS(1:2) TO WS-TS-HOUR.
MOVE WS-TIME-SYS(3:2) TO WS-TS-MIN.
MOVE WS-TIME-SYS(5:2) TO WS-TS-SEC.
STRING WS-TS-DATE-FMT " " WS-TS-TIME-FMT
INTO WS-TIMESTAMP-OUT
END-STRING.
@@ -0,0 +1,20 @@
KEY NAME BALANCE
RANGE START FAILED
=== BATCH CONTROL TOTALS ===
Total search requests : 04==
Total records found : 00==
Total records not found: 01=
=== OPERATION TYPE STATISTICS ===
By-key searches : 01ATISTICS ===
Range searches : 01ATISTICS ===
Greater searches : 01ATISTICS ===
=== DATA INTEGRITY HASH TOTALS ===
Hash total (CUST-BALANCE sum): 000000000000
=== SEARCH PERFORMANCE METRICS ===
Total READs (by-key) : 02S ===
Total READs (range) : 00S ===
Total READs (greater-than): 00 ===
@@ -0,0 +1,4 @@
BY-KEY | KEY=CUST000003 FOUND=00 FAILED | 2026/06/22
RANGE | LOW=CUST000002 HIGH=CUST000005 FOUND=00 | 2026/06/22
BY-KEY | KEY=ZZZZZZZZZZ FOUND=00T000005 FOUND=00 | 2026/06/22
GREATER-THAN | KEY>CUST000003 FOUND=00T000005 FOUND=00 | 2026/06/22