Mainframe Tips, Tricks And Tutorials
Mainframe tips
Saturday, July 25, 2026
𝗢𝗽𝘁𝗶𝗺𝗶𝘇𝗶𝗻𝗴 𝗮 𝗠𝗶𝗰𝗿𝗼 𝗙𝗼𝗰𝘂𝘀 𝗖𝗢𝗕𝗢𝗟 𝗣𝗿𝗼𝗴𝗿𝗮𝗺: 𝗥𝗲𝗱𝘂𝗰𝗶𝗻𝗴 𝗥𝘂𝗻𝘁𝗶𝗺𝗲 𝗳𝗿𝗼𝗺 𝟲𝟬 𝘁𝗼 𝟭𝟱 𝗠𝗶𝗻𝘂𝘁𝗲𝘀
𝗔 𝗦𝗶𝗺𝗽𝗹𝗲 𝗧𝗲𝗰𝗵𝗻𝗶𝗾𝘂𝗲 𝘁𝗼 𝗘𝗻𝘀𝘂𝗿𝗲 𝗢𝗻𝗹𝘆 𝗢𝗻𝗲 𝗝𝗼𝗯 𝗥𝘂𝗻𝘀 𝗮𝘁 𝗮 𝗧𝗶𝗺𝗲 𝗶𝗻 𝗮 𝗚𝗿𝗼𝘂𝗽 𝗼𝗳 𝗣𝗮𝗿𝗮𝗹𝗹𝗲𝗹 𝗝𝗼𝗯𝘀
As a result:
- The
first job that acquires the dataset proceeds normally.
- Any
other job that also requests the same dataset with DISP=OLD must wait
until the dataset is released.
- Since the DD statement is present in the last step of each job, the dataset remains allocated until that step completes, effectively ensuring that only one job from the group runs at a time.
Monday, July 20, 2026
Why Binary Fields Never Cause an S0C7 Abend, but Zoned Decimal and Packed Decimal Can
Binary fields will NEVER cause S0C7 abend
This is demonstrated using the below COBOL code.
WORKING-STORAGE SECTION.
01 JUNK PIC X(04).
01 WS-BINARY REDEFINES JUNK PIC 9(08) COMP.
PROCEDURE DIVISION.
MOVE 'ABCD' TO JUNK.
DISPLAY 'WS-BINARY: ' JUNK WS-BINARY
ADD 1 TO WS-BINARY
DISPLAY 'WS-BINARY: ' JUNK WS-BINARY
MOVE '#$%=' TO JUNK.
DISPLAY 'WS-BINARY: ' JUNK WS-BINARY
ADD 1 TO WS-BINARY
DISPLAY 'WS-BINARY: ' JUNK WS-BINARY
WS-BINARY: 50766789
WS-BINARY: 69589118
WS-BINARY: 69589119
'ABCD' is indirectly moved to WS-BINARY. The hexadecimal equivalent of 'ABCD' is X’C1C2C3C4’. If you put this HEX decimal value in calculator, you will get 3,250,766,788. Since picture clause of WS-BINARY is 9(8), the last 8 digit 50,766,788 is displayed in the first DISPLAY statement.
When you add 1 to this value(3,250,766,788), it become 3,250,766,789 and second DISPLAY statement displays last 8 digits which is 50,766,789.
Case 2: Value "#$%="
'#$%=' is indirectly moved to WS-BINARY. The hexadecimal equivalent of '#$%=' is X’7B5B6C7E’. If you put this HEX decimal value in calculator, you will get 2,069,589,118. Since picture clause of WS-BINARY is 9(8), the last 8 digit 69,589,118 is displayed in the third DISPLAY statement.
When you add 1 to this value(2,069,589,118), it become 2,069,589,119 and fourth DISPLAY statement displays last 8 digits which is 69,589,119.
Typical zoned decimal declarations in COBOL are shown below:
01 WS-NUMBER1 PIC 9(5). -> Unsigned zoned decimal
01 WS-NUMBER1 PIC 9(5)V99. -> Unsigned zoned decimal
01 WS-NUMBER2 PIC S9(5)V99. -> Signed zoned decimal
Internal representation of Zoned Decimal in Memory
In a zoned decimal field:
- Each decimal digit occupies one byte.
- Each byte has 2 nibbles, and each nibble has 4 bits.
- The high-order 4 bits (zone portion) of each byte will always have b’1111’ (hex F) except the last byte.
- The low-order 4 bits (decimal portion) contain the actual numeric digit (0–9).
- In the last byte, first 4 bits will store the sign and second 4 bits will store the last numeric digit.
|
Value |
Internal Hex Representation |
|
Unsigned 12345 |
X'F1F2F3F4F5' |
|
+12345 |
X'F1F2F3F4A5' X'F1F2F3F4C5' X'F1F2F3F4E5' |
|
-12345 |
X'F1F2F3F4B5' X'F1F2F3F4D5' |
Sign is stored in the zone portion (high-order 4 bits) of the last byte. Valid signs are given below
|
Sign |
Zone Nibble |
|
Unsigned |
F |
|
Positive |
A,C,E |
|
Negative |
B,D |
01 WS-9 PIC S9(05).
01 WS-X REDEFINES WS-9 PIC X(05).
PROCEDURE DIVISION.
PARA1.
MOVE X'F1F2F3F4F5' TO WS-X
PERFORM CHECK-SIGN
MOVE X'F1F2F3F4A5' TO WS-X
PERFORM CHECK-SIGN
MOVE X'F1F2F3F4C5' TO WS-X
PERFORM CHECK-SIGN
MOVE X'F1F2F3F4E5' TO WS-X
PERFORM CHECK-SIGN
MOVE X'F1F2F3F4B5' TO WS-X
PERFORM CHECK-SIGN
MOVE X'F1F2F3F4D5' TO WS-X
PERFORM CHECK-SIGN
GOBACK.
CHECK-SIGN.
IF WS-9 > 0
DISPLAY WS-9 ' POSITIVE'
ELSE
IF WS-9 = 0
DISPLAY WS-9 ' ZEROS'
ELSE
DISPLAY WS-9 ' NEGATIVE'
END-IF
END-IF.
ADD 1 TO WS-9
DISPLAY 'WS-X : ' WS-X.
|
Output of the program is given below |
Hex value for the number displayed |
|
12345 POSITIVE |
X'F1F2F3F4F5' |
|
WS-X : 1234F |
X'F1F2F3F4C6' |
|
1234v POSITIVE |
X'F1F2F3F4A5' |
|
WS-X : 1234F |
X'F1F2F3F4C6' |
|
1234E POSITIVE |
X'F1F2F3F4C5' |
|
WS-X : 1234F |
X'F1F2F3F4C6' |
|
1234V POSITIVE |
X'F1F2F3F4E5' |
|
WS-X : 1234F |
X'F1F2F3F4C6' |
|
1234§ NEGATIVE |
X'F1F2F3F4B5' |
|
WS-X : 1234M |
X'F1F2F3F4D4' |
|
1234N NEGATIVE |
X'F1F2F3F4D5' |
|
WS-X : 1234M |
X'F1F2F3F4D4' |
Typical packed decimal declarations in COBOL are shown
below:
01 WS-NUMBER1 PIC 9(5) COMP-3.
-> Unsigned packed decimal
- Each byte has two decimal digits except the last byte
- In the last byte, first 4 bits will store the numeric digit and second 4 bits will store the sign.
- If an odd number of digits exists, the unused high-order nibble is padded with zero.
|
Value |
Internal Hex Representation |
|
Unsigned 12345 |
X'12345F' |
|
+12345 |
X'12345A' X'12345C’ X'12345E’ |
|
-12345 |
X'12345B' X'12345D’ |
|
+123456 |
X’0123456C’ |
Similar to zoned decimal, system always uses “C” for positive signs and “D” for negative signs for packed decimals, but still accepts A,B,E signs
01 JUNK PIC X(04).
01 WS-ZONED-DECIMAL REDEFINES JUNK PIC 9(04).
PROCEDURE DIVISION.
MOVE 'ABCD' TO JUNK.
DISPLAY 'WS-ZONED-DECIMAL: ' WS-ZONED-DECIMAL
ADD 1 TO WS-ZONED-DECIMAL
DISPLAY 'WS-ZONED-DECIMAL: ' WS-ZONED-DECIMAL
MOVE X'1A1B1C1D' TO JUNK.
DISPLAY 'WS-ZONED-DECIMAL: ' WS-ZONED-DECIMAL
ADD 1 TO WS-ZONED-DECIMAL
DISPLAY 'WS-ZONED-DECIMAL: ' WS-ZONED-DECIMAL
GOBACK.
WS-ZONED-DECIMAL: 1235
WS-ZONED-DECIMAL: X'1A1B1C1D'
Code Explanation
Mainframe does not have any instruction to perform arithmetic operations on zoned decimals. So, it first converts zoned-decimals to packed-decimal and then performs arithmetic operations on the packed-decimal.
The first move indirectly populated ‘ABCD’(hex value X’C1C2C3C4’) to WS-ZONED-DECIMAL.
Before adding one to WS-ZONED-DECIMAL, Value X’C1C2C3C4’ need to be converted to packed-decimal.
How Zoned Decimal to Packed Decimal Conversion Works
During the conversion process:
- The digit portion of each zoned-decimal byte is treated as a numeric digit.
- The zone bits are ignored except in the rightmost byte.
- The zone bits of the last byte become the sign nibble.
- Digits are packed together from left to right.
- If the packed-decimal result contains an unfilled nibble, it is padded with zero on the left.
Example 1: ‘ABCD’ - X'C1C2C3C4'
Value X’C1C2C3C4’ becomes X‘01234C’ after zoned-decimal to packed-decimal conversion.
Therefore, the second DISPLAY statement shows 1235, because the temporary packed-decimal representation (X'01234C') was successfully incremented by one during the arithmetic operation.
Example 2: X'1A1B1C1D'
Value X'1A1B1C1D' becomes X‘0ABCD1’ after zoned-decimal to packed-decimal conversion.
Since X‘0ABCD1’ does not adhere to packed-decimal representation, when we tried to add one to it, system produced S0C7 abend
As discussed earlier, a packed-decimal field must conform to the valid packed-decimal format. If the field contains invalid digits or an invalid sign nibble and an arithmetic operation is attempted on it, the processor detects the invalid data and raises an S0C7 (Data Exception) abend.
Sunday, July 19, 2026
How We Eliminated DB2 table Contention Across 50 Batch Jobs Using ESP Renewable Resources
RUN WORKDAYS
REL JOBXXX
NOTWITH(JOB2, JOB3, JOB4, ... JOB50)
ENDJOB
RUN WORKDAYS
REL JOBYYY
NOTWITH(JOB1, JOB3, JOB4, ... JOB50)
ENDJOB
RUN WORKDAYS
REL JOBXXX
RESOURCE (1,MY_TABLE)
ENDJOB
RUN WORKDAYS
REL JOBYYY
RESOURCE (1,MY_TABLE)
ENDJOB
RUN WORKDAYS
REL JOBZZZ
RESOURCE (1,MY_TABLE)
ENDJOB
- If the resource is available, the job starts immediately.
- If the resource is already in use, ESP holds the job until the resource becomes available.
- Once the job completes, regardless of whether it ends successfully or abends, the resource is automatically returned to the pool.
- Eliminated table update contention between batch jobs.
- Removed the need for complex and difficult-to-maintain NOTWITH definitions.
- Simplified scheduling logic significantly.
- Reduced month-end job abends caused by concurrent updates.
Thursday, July 16, 2026
What Happens When You Run SELECT COUNT(*) on a Large DB2 Table?
|
Metric |
Value |
|
Row Count |
120,632,075 |
|
Average Row
Length |
95 bytes |
|
Used Pages |
3,093,397 |
|
Space
Utilized |
13,631,040 KB |
|
Index |
Allocated Space (KB) |
Leaf Pages |
Levels |
Avg. Key Length |
|
Index_1 |
15,730,560 |
3,655,518 |
6 |
101 |
|
Index_2 |
13,633,200 |
3,165,273 |
5 |
84 |
|
Metric |
Value |
|
Row Count |
1,006,831,073 |
|
Average Row
Length |
30 bytes |
|
Used Pages |
8,078,681 |
|
Space
Utilized |
32,506,560 KB |
|
Index |
Allocated Space (KB) |
Leaf Pages |
Levels |
Avg. Key Length |
|
Index_1 |
30,412,080 |
7,507,065 |
5 |
18 |
|
Index_2 |
30,412,080 |
7,507,065 |
5 |
18 |
|
Index_3 |
30,412,080 |
7,507,065 |
5 |
18 |
|
Index_4 |
7,341,840 |
1,726,625 |
4 |
5 |
|
Index_5 |
7,341,840 |
1,731,545 |
4 |
11 |
|
Index_6 |
30,412,080 |
7,507,065 |
5 |
18 |
|
Index_7 |
39,849,840 |
9,773,348 |
5 |
24 |
- If all indexes are as large as—or larger than—the table, DB2 may perform a table space scan.
- If a smaller, efficient index exists, DB2 may perform an index scan and count index entries instead.
Wednesday, July 15, 2026
Ignoring COBOL File Status Checks Led to Silent Data Loss
At first glance, it looked like a straightforward COBOL batch program.
It read a sequential file from beginning to end. For each
record, it performed a random lookup in a KSDS file. If a matching record
existed, it updated the record. If no match was found, it inserted a new record
into the KSDS file.
Hidden deep within the program was a critical flaw: after
every write operation, the program never checked the file status code to verify
whether the write had succeeded.
Everything worked perfectly—until the KSDS file reached its
maximum size limit of 4 GB.
Once that limit was reached, every attempt to add a new
record failed. The system dutifully generated the message:
IEC070I 034(004)-220
However, because the program never validated the write
status, it continued processing records as if every insert had been successful.
The result?
New records were silently discarded while the batch job
completed normally, giving everyone the illusion that everything was working as
intended.
The issue remained undetected for months, quietly
preventing new data from being added to the KSDS file until someone finally
traced the missing records back to the unnoticed write failures.
Key Takeaway : Never assume a file operation succeeds.
After every file read, write, rewrite, delete, or
open operation:
✅ Check the file status code.
✅
Handle error conditions appropriately.
✅
Log and escalate failures when necessary.