Saturday, April 18, 2026

Limiting Storage use above the bar in z/Architecture

As in the 31-bit address space, a virtual "line" marks the 16-megabyte address. The 64-bit address space also includes the virtual line at the 16-megabyte address; additionally, it includes a second virtual line called the bar that marks the 2-gigabyte address. The bar separates storage below the 2-gigabyte address, called below the bar, from storage above the 2-gigabyte address, called above the bar. The area above the bar is intended for data; no programs run above the bar. There is no area above the bar that is common to all address spaces, and no system control blocks exist above the bar. You can set a limit on how much virtual storage above the bar each address space can use. This limit is called the MEMLIMIT . If you do not set MEMLIMIT, the system default is 0, meaning no address space can use virtual storage above the bar (Use of real storage above the 2GB is not controlled by this parameter). If you want to use virtual storage above the bar, you need to set the MEMLIMIT explicitly. You can set an installation default MEMLIMIT through SMFPRMxx in PARMLIB. You can also set MEMLIMIT for a specific address space in the JCL that creates the address space or by using SMF exit IEFUSI.

To use virtual storage above the bar, a program must request storage above the bar, be in AMODE 64 and use the new z/Architecture assembler instructions.

SMF MEMLIMIT Parameter 

An installation can set the default MEMLIMIT through SMFPRMxx in PARMLIB.

MEMLIMIT(NOLIMIT)

nnnnnM

nnnnnG

nnnnnT

nnnnnP

This specifies the default MEMLIMIT to be used by jobs not establishing a MEMLIMIT in their JCL. For reference see z/OS MVS JCL User's Guide . NOLIMIT means that there is no limit on the use of virtual storage above 2 gigabytes.

MEMLIMIT values are defined with nnnnnM for megabytes, nnnnnG for gigabytes, nnnnnT for terabytes, or nnnnnP for petabytes. For example, to request 1200 gigabytes, you can specify MEMLIMIT(1200G). D SMF,O operator command displays the current MEMLIMIT, as shown in example below:

RESPONSE=SYSA

IEE967I 15.39.05 SMF PARAMETERS 795

MEMBER = SMFPRMZ3

MULCFUNC -- DEFAULT

MEMLIMIT(00000M) -- DEFAULT

DDCONS(YES) -- DEFAULT

LASTDS(MSG) -- DEFAULT

NOBUFFS(MSG) -- DEFAULT

DUMPABND(RETRY) -- DEFAULT

SUBSYS(OMVS,NODETAIL) -- SYS

SUBSYS(OMVS,TYPE(0,30,70:79,88:90,103,245)) -- PARMLIB

SUBSYS(OMVS,INTERVAL(SMF,SYNC)) -- PARMLIB

SUBSYS(OMVS,NOEXITS) -- PARMLIB

SUBSYS(STC,NODETAIL) -- SYS

Note: If MEMLIMIT is not specified in SMFPRMxx, the default value is 0M.

MEMLIMIT on JOB and EXEC Statement 

MEMLIMIT is a new keyword on the JOB and EXEC statements. MEMLIMIT specifies the limit on the total number of usable virtual storage above the bar for a single address space.

While there is no practical limit to the virtual storage above the bar, there are practical limits to the real storage frames and auxiliary storage slots backing the virtual storage area. To control the amount of real and auxiliary storage an address space can use for memory objects at one time, your installation should establish an installation default MEMLIMIT to set the total amount of usable virtual pages above the bar for a single address space. You set this default on the MEMLIMIT parameter in the SMFPRMxx parmlib member, or through the SET SMF or SETSMF commands. This default takes effect if a job does not specify MEMLIMIT on the JOB or an EXEC statement or REGION=0M in the JCL; the MEMLIMIT specified in an IEFUSI exit routine overrides all other MEMLIMIT settings.

The system enforces the MEMLIMIT when you issue the IARV64 GETSTOR and CHANGEGUARD services. When your unconditional request for new storage (either for a new memory object or for more usable storage in an existing memory object) causes the MEMLIMIT to be exceeded, the system abends the program. IBM recommends programs use the COND parameter to make a conditional request and check the return code to make sure the storage is available.

What happens to the MEMLIMIT for an already-created address space if a SET SMF or SETSMF command changes the default MEMLIMIT (either the system default or the installation default)?

If the command raises the current default MEMLIMIT, all address spaces whose MEMLIMIT was set through SMF run with the higher default.

If the command lowers the current default MEMLIMIT, all address spaces whose MEMLIMIT was set through SMF keep their original system default.

A SET SMF or SETSMF command cannot change the MEMLIMIT value set through JCL or by an IEFUSI installation exit.

MEMLIMIT Enforcement Through IEFUSI 

The SMF IEFUSI exit can change the MEMLIMIT value by updating the value in the third double word. But the publication failed to mention the value used is in the unit of MB (for example, 00000000 00008400 is 33 GB).

The z/OS 1.2 MVS Installation Exits manual does not describe the meaning of the flags in the first double word. The z/OS 1.2 book contains a NOLIMIT value of FFFFFFFF FFFFF000, which is incorrect. Both of these errors have been corrected in the z/OS 1.3 publication. The z/OS 1.2 and z/OS 1.3 books do not mention the unit of MB in the third double word

When IEFUSI Exit receives control, Register 1 points to a list of addresses. Word 9 contains the address of an area, as described in the z /OS 1.3 MVS Installation Exits :

 Word 9 

 The address of an area consisting of three 64-bit fields: 

 | A 64-bit flagword. The first 8 bits indicate whether the 

 | source of the MEMLIMIT is from JCL or the SMF-supplied 

 | system default. The remaining 56 bits are not used. Possible 

 | values for the first 8 bits, and their meanings are as 

 | follows: 

 | 01 -- indicates MEMLIMIT is from SMF 

 | 02 -- indicates MEMLIMIT is from JCL 

 | 03 -- indicates MEMLIMIT was set to NOLIMIT because JCL 

 | specified REGION=0 

 | FF -- indicates MEMLIMIT is from SMF (indicative of 

 | internal processing errors) 

 | Note: Other values are possible when initializing a child 

 | address space in the UNIX System Services 

 | environment. See UNIX System Services publications 

 | for more information. 

 | The 64-bit MEMLIMIT originally requested by the source that 

 | is specified in the flagword. 

 | The 64-bit MEMLIMIT requested by the IEFUSI exit. The 

 | initial value is X'FFFFFFFFFFFFFFFF' to indicate that no 

 | value was set by the exit. If not changed, SMF uses the 

 | MEMLIMIT that was originally requested. 

 Note: A MEMLIMIT of NOLIMIT is equivalent to X'00000FFFFFFFF000'. 

The REGION JCL Parameter

The below article was written by by Jim Moore NASPA website which is no longer available

The REGION JCL Parameter

I have wanted to write this column for a long time. The JCL REGION parameter is one of the most confusing of all JCL parameters. Using it correctly can be crucial to getting vastly improved throughput for many batch jobs. The confusion about the REGION parameter stems from many factors. Some are historical. Others are due to misconceptions. I will attempt to explain as many of these factors as possible and hopefully, clarify the REGION parameter's usage.

REGION does NOT acquire storage
This is the first misunderstanding that needs clarification. I'll state this as: If a REGION= parameter is coded in a JCL stream or at TSO logon, this DOES NOT cause any storage to be acquired by the operating system. Or, if I code "REGION=0M" on a job card, my job does NOT attempt to GETMAIN all of the virtual storage on the operating system.

Coding a REGION parameter influences only two data values within a control block known as the Local Data Area (LDA, DSECT IHALDA). These two binary fullword values store the maximum amount of virtual storage that address spaces can GETMAIN. Be clear on this: Programs being executed acquire storage. Not the JCL itself.

Why two values? Simple. One field stores the 24-bit ("below the 16 megabyte line") maximum and the other stores the 31-bit ("above the 16 megabyte line") maximum. This dual nature of the REGION parameter, limiting both 24 and 31 bit storage, is critical and will be fully explained later.

Jobcard Coded REGION Overrides Step-Coded REGION
At first, this might seem a bit upside down. Doesn't coding a STEPLIB override any JOBLIB that might be coded? It seems natural that a step-coded value would override the global declaration from the jobcard.

It doesn't work that way. The STEPLIB/JOBLIB situation is an exception. If you code a REGION=50M on your jobcard, it will apply to all steps in the job – even steps that code a different REGION value.

Knowing that the REGION declaration doesn't actually acquire any storage but instead, establishes a limit, I recommend always coding REGION on the jobcard.

Defaults and Exits
This is where the REGION processing gets tricky. I am going to try to explain this as clearly as possible but be forewarned: The defaults and exit-modified values for REGION vary widely from installation to installation. I can't speak to absolutes here because every single z/OS site usually has a different set of default values.

To begin, ask yourself: What if a REGION parameter is not even coded? What limiting values will end up in the LDA? Figure 1 describes how to use the BROWSE command of DDLIST under TSO/ISPF to locate and examine the LDA for your TSO session.

What is the default for REGION?
All REGION discussion that follows applies to what are known as "V=V (or ADDRSPC=VIRT) type of job steps – 99.999% of all work on z/OS.

There is a single question to ask and get answered before you can accurately determine the default limiting amounts for REGION at your site. That question is:

Has your installation established their own defaults by way of either the IEFUSI or IEALIMIT exits? Or, have IBM's "factory defaults" been left in place?

REGION Values Fall Into Ranges
Much of the following discussion is based upon the explanations in Section 16.13.3 – REGION Defaults – in the z/OS V1R6 MVS JCL Reference manual. I suggest reading this bit of IBM documentation in conjunction with my explanations. I have tried to simplify things a bit and to underscore the fact that the values coded on a REGION parameter fall into ranges when it comes to what type of REGION you are seeking to limit.

REGION=0M or REGION=0K
The value of zero is a special case. Coding a zero REGION size sets the limits to all of the 24-bit and 31-bit virtual storage available to the address space. Typical defaults are between 8M-10M for 24-bit storage and between 1600M-1900M for 31-bit storage. It DOES NOT acquire any memory and may be further limited by an IEALIMIT or IEFUSI exit.

Also, remember that the REGION parameter applies only to virtual storage limits for the address space (job, step, TSU, etc) that it is coded on. To view the available private storage for an address space (the REGION= amount you can potentially use), you would need an RMF post processor VSTOR report or some other tool that displays a virtual storage map – something like Mark Zelden's IPLINFO REXX exec, TASID, ShowMVS or MXI. If your site has one installed, MVS monitors like OMEGAMON, TMON and MAINVIEW can also display a virtual storage map.

REGION=1K through REGION=16384K
When you code a value between 1K and 16M (note that 16384K = 1,024 X 16), the limit will be applied only to 24-bit storage. For the 31-bit limit, the job will either get the IBM default of 32M or an exit-modified 31-bit limit value.

Note that there is a range of "below the line" limiting values that I will call impossible values. These values fall between approximately REGION=8192K-16384K. If an exit doesn't intercept these impossible values and alter them dynamically (to an amount less than the 24-bit maximum amount), your job will get an S822 abend every time if it uses REGION values in the impossible range. Refer to Figure 2 for a simple piece of JCL to test for the impossible REGION values.

If this one-step IEFBR14 (with no DD names) gets an S822 when using REGION values in the impossible range, this is a good indication that no exits are in place that are dynamically altering REGION limits.

REGION=16385K through REGION=32768K
REGION values between 16M (+ 1K) up to and including exactly 32M limits the job step to the defined site maximum for 24-bit storage. The 31-bit limit will always be either 32M or an exit-modified 31-bit limit value.

REGION=32769K through REGION=2047M
REGION values between 32M (+ 1K) up to and including exactly 2047M limits the job step to the defined site maximum for 24-bit storage. The 31-bit limit will be either the coded value or an exit-modified 31-bit limit value.

In the IBM documentation, the following sentence appears several times when describing how the region below 16 megabytes might be influenced:

"The resulting size of the region below 16 megabytes depends on system options and what system software is installed."

This varies from site to site but a typical default maximum for "below the line" storage is between 9M-10M. In other words, no job step can EVER request more below the line storage than this. If it does, this is considered an impossible REGION value and either your job will abend with an S822 or the impossible value will be lowered by an exit.

Conclusion
Certainly, the REGION parameter of z/OS JCL is one of the most confusing of all JCL parameters. One thing to keep in mind is the very nature of a language such as JCL. JCL, like HTML, is what I call a "static" language. It is designed to create a framework for the invocation of programs, nothing more. It doesn't have the capability of taking its own actions. All of its many keywords and parameters define existing or newly created run-time components. Some JCL parameters set limits or establish other run-time variables but JCL itself has no ability to acquire storage, move values or do anything other than establish a run-time environment for programs.

With this in mind, remember these three key things about how the REGION parameter influences virtual storage in a z/OS JCL stream:

1) It NEVER acquires any storage. It only sets limits.
2) A REGION value coded on the job card overrides any step-coded values.
3) The values coded fall into ranges. Below 16M, the REGION value limits 24-bit storage. Above 32M, you are limiting 31-bit storage.


Figure 1 – Using the BROWSE command of DDLIST to locate and examine the Local Data Area of your TSO session. This chaining can be followed in any z/OS address space to locate and examine the LDA for storage used and maximum allowed. Note that TSO sessions (TSU) usually have a different default for a 24-bit storage limit than stock batch jobs.


· Invoke DDLIST at any ISPF command line.
· Once in DDLIST, type: BROWSE 224. <- period required, at the command line. This is the address of your TSO session's ASCB.
· Type: BROWSE and move the cursor anywhere within the address at +0 on the screen and press enter (a "point-and-shoot" BROWSE). At the next screen, look for the eye-catching literal "ASCB" in the memory translation area.
· Type: BROWSE and move the cursor anywhere within the address at +30 into the ASCB and press enter. The LDA address is typically very high in memory (begins with X'7F').
· You should now be viewing the LDA of your TSO session. Look for the eye-catching literal "LDA" in the memory translation area at the most recent address that you BROWSED.
· The following offsets into the LDA hold the REGION values:


X'D8' – Maximum amount of 31-bit storage allowed for your TSO session
X'F0' – Current amount of used 31-bit storage
X'D0' - Maximum amount of 24-bit storage allowed for your TSO session
X'E8' – Current amount of used 24-bit storage
X'CC' – The REGION value from either a LOGON screen (possibly defaulted) or an exit

Note that all of these values are fullword binary integers that will need to be converted from hex into decimal.

As an experiment, split the screen and get into edit on a large dataset. Return to the LDA display and press enter, watching the value at X'F0' (current amount of used 31-bit storage). Did it increase?

For the full context of the LDA, refer to DSECT IHALDA.


Figure 2 – Testing for impossible REGION values. Begin with a REGION=9000K and then increment the REGION value – either by K or by M. If you do not get an S822 abend, an exit is intercepting and changing the impossible REGION value. No DD names are needed. Simply code an EXEC line naming PGM=IEFBR14 with a REGION parameter. Add a job card but do not code a REGION on the job card.

//add a jobcard
//*
//TESTS822 EXEC PGM=IEFBR14,REGION=9000K

Below is a sample COBOL program that displays current/maximum REGION values below and above the line.

       ID DIVISION.
       PROGRAM-ID.  REGION.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       LINKAGE SECTION.

      * --- MAP PSA  --------------------------------------
       01  PSA.
           02   FILLER                 PIC X(548).
           02   PSAAOLD                POINTER.

      * --- MAP ASCB  -------------------------------------
      * MACRO IHAASCB
       01  ASCB.
           02   FILLER                 PIC X(48).
           02   ASCBLDA                POINTER.
           02   FILLER                 PIC X(120).
           02   ASCBJBNI               POINTER.
           02   ASCBJBNS               POINTER.

      * MACRO IHALDA
       01  LDA.
           02   FILLER                 PIC X(204).
      * REGION SIZE REQUESTED IF LDAREGNX = 1, ADJUSTED SUM OF BOTH
      * REGIONX PARAMETERS
      * THE REGION VALUE FROM EITHER A LOGON SCREEN (POSSIBLY DEFAULTED)
      * OR AN EXIT
           02   LDAREGRQ               PIC 9(09) COMP-5.
      * < 16M V=V REGION LIMIT VALUE
      * MAXIMUM AMOUNT OF 24-BIT STORAGE ALLOWED
           02   LDALIMIT               PIC 9(09) COMP-5.
           02   FILLER                 PIC X(04).
      * > 16M V=V REGION LIMIT VALUE
      * MAXIMUM AMOUNT OF 31-BIT STORAGE ALLOWED
           02   LDAELIM                PIC 9(09) COMP-5.
           02   FILLER                 PIC X(12).
      * < 16M USER REGION ALLOC VALUE
      * CURRENT AMOUNT OF USED 24-BIT STORAGE
           02   LDALOAL                PIC 9(09) COMP-5.
           02   FILLER                 PIC X(04).
      * > 16M USER REGION ALLOC VALUE
      * CURRENT AMOUNT OF USED 31-BIT STORAGE
           02   LDAELOAL               PIC 9(09) COMP-5.

       01  STCNAME                     PIC X(8).
       01  JOBNAME                     PIC X(8).

       PROCEDURE DIVISION.
           SET ADDRESS OF PSA TO NULL.
           SET ADDRESS OF ASCB TO PSAAOLD.
           SET ADDRESS OF JOBNAME TO ASCBJBNI.
           SET ADDRESS OF STCNAME TO ASCBJBNS.
           DISPLAY "(DZSCOB1) " STCNAME ", " JOBNAME.
           DISPLAY "ASCB: " ASCB(1:4)
           SET ADDRESS OF LDA     TO ASCBLDA
           DISPLAY 'THE REGION VALUE FROM EITHER A LOGON SCREEN OR'
                   ' AN EXIT : ' LDAREGRQ
           DISPLAY 'MAXIMUM AMOUNT OF 24-BIT STORAGE ALLOWED : '
                LDALIMIT
           DISPLAY 'MAXIMUM AMOUNT OF 31-BIT STORAGE ALLOWED : '
                LDAELIM
           DISPLAY 'CURRENT AMOUNT OF USED 24-BIT STORAGE : '
                LDALOAL
           DISPLAY 'CURRENT AMOUNT OF USED 31-BIT STORAGE : '
                LDAELOAL
           GOBACK.

Friday, April 17, 2026

Viewing the IEAOPTxx settings currently in use through RMF Monitor

IEAOPTxx is a PARMLIB member that significantly influences processing by WLM, SRM, and the Supervisor.

To view your active IEAOPTxx parameters, go to RMF Monitor II, select Option L (Program Library and OPT Information), and then choose Option 4. Alternatively, once you are in RMF Monitor II, you can simply type OPT on the command line to display all IEAOPTxx parameters.

From Option L, you can also view the LNKLSTxx, LPALSTxx, and IEAAPFxx lists.

                     RMF Monitor II Primary Menu                   z/OS V2R5 RMF
 Selection ===>                                                                 
                                                                                
          
   1 Address Spaces      Address space reports                                  
   2 I/O Subsystem       I/O Queuing, Device, Channel, and HFS reports          
   3 Resource            Enqueue, Storage, SRM, and other resource reports      
                                                                                
   L Library Lists       Program library and OPT information                    
   U User                User-written reports (add your own...)                 
                                                                                


           RMF Monitor II Library List and OPT Settings Selection Menu          
 Selection ===>                                                                 
                                                                                                                                                     
   1 Link list         LNKLSTxx - Link Library list                        (LLI)
   2 LPA list          LPALSTxx - LPA Library List                     (LLI LPA)
   3 APF list          IEAAPFxx - Authorized Program List              (LLI APF)
                                                                                
   4 OPT               IEAOPTxx - OPT Settings                             (OPT)
                                                                                
                                                                                

                             RMF - OPT Settings                    Line 1 of 41 
 Command ===>                                                  Scroll ===> CSR  
                                                                                
                         CPU= 12/ 12 UIC= 65K PR=   0         System= XXXX Total
                                                                                
 OPT: 00            Time: N/A                                                   
 -- Parameter --  - Default - -- Value -- Unit ---------- Description ----------
                                                                                
 ABNORMALTERM             Yes         Yes Y/N  Abnormal terminations in routing 
 ABSMSUCAPPING             No          No Y/N  Absolute, permanent MSU capping  
 BLWLINTHD                 20          20 sec  Time blocked work waits for help 
 BLWLTRPCT                  5           5 0/00 CPU cap. to promote blocked work 
 CCCAWMT                 3200        3200 usec Alternate wait management time   
 CCCSIGUR                  45          19 msec Min. mean-time-to-wait threshold 
 CNTCLIST                  No         Yes Y/N  Clist commands count individually
 CPENABLE                 0,0        5,15 %    Threshold for TPI (low,high)     
 DVIO                     Yes         Yes Y/N  Directed VIO is active           
 ERV                      500    50000/CB SU   Enqueue residency CPU Service/DP 
 FULLPRESYSTEM             No          No Y/N  System AS can preempt other work 
 HIPERDISPATCH            Yes         Yes Y/N  Hiperdispatch is desired/active  
 IFAHONORPRIORITY         Yes         Yes Y/N  Allows CPs to help zAAPs         
 IIPHONORPRIORITY         Yes         Yes Y/N  Allows CPs to help zIIPs         
 INITIMP                    0        1/F0 #    INITIMP value/DP for initiators  
 IRA405I             70,50,50    70,50,50 %    Fixed storage of <16M,16M-2G,tot 


The above information was copied from https://community.ibm.com/community/user/blogs/anthony-giorgio2/2020/04/02/viewing-your-current-ieaoptxx-settings

Monday, April 6, 2026

XCOM Data Transfer experiencing dataset contention

Recently, we encountered an issue where an XCOM data transfer from a production batch job was failing due to dataset contention. At first glance, this was puzzling—because the dataset involved was used by only this single job. This post walks through the root cause of the problem and the simple yet effective solution, with reference to JCL behavior.
 
Job Overview
 
The batch job in question consisted of the following steps:
 
Step 1 – Delete the dataset TEST.XCOM.FILE
Step 2 – Executes some COBOL program to create TEST.XCOM.FILE
Step 3 – Perform XCOM data transfer using TEST.XCOM.FILE
Step 4 – Send an email with TEST.XCOM.FILE as an attachment
 
Importantly, no other job uses TEST.XCOM.FILE.
 
So the natural question arises:
 
How can an XCOM data transfer run into dataset contention when the job that created the file is the one initiating the transfer?
 
 
The Unexpected Cause of Contention
 
The key lies in how XCOM handles data transfer requests.
 
The XCOM step has PARM='TYPE=SCHEDULE' which means it queues the file transfer request and ends the job step when the transfer request is queued. So, the XCOM step in the job (Step 3) does not perform the data transfer synchronously. Instead, it submits the transfer request to the XCOM started task and immediately completes. This allows the job to continue executing Step 4 without waiting for the actual data transfer to finish.
 
While Step 4 was running—sending an email and attaching TEST.XCOM.FILE—the XCOM started task attempted to access the same dataset to perform the transfer. At this point, the dataset was still held by the job in exclusive mode, resulting in contention and a failed transfer.
 
Why the Dataset Was Still Locked
 
This behavior is clearly explained in the JCL Language Reference Manual, specifically in Chapter 12.19 (DISP parameter).
 
Key points from the manual:
 
  • Before a job starts, the initiator issues an ENQ (enqueue) for every dataset used in the job.
  • The highest level of control required by any step determines the ENQ type:
    • DISP=SHR → Shared (SHR)
    • DISP=NEW, MOD, or OLD → Exclusive (EXCL)
  • ENQs cannot be downgraded during job execution.
  • The ENQ is released only at the end of the last step that references the dataset.
 
Since the job creates TEST.XCOM.FILE, it had exclusive (EXCL) control over the dataset.  Because Step 4 also references TEST.XCOM.FILE, the ENQ remains held until Step 4 completes.
 
As a result, when the XCOM started task attempted to transfer the file, the dataset was still exclusively locked by the job itself.
 
The Solution
 
The fix was straightforward:
 
Move the XCOM data transfer step to the very end of the job.
 
By doing so:
  • When the XCOM started task begins the actual transfer, the dataset is no longer held by the job.
  • The transfer proceeds without contention.
 
From the JCL Language Reference Manual, Chapter 12.19 (DISP parameter):

DISP and ENQ: Before starting the first step of a job, the initiator requests control of all of the data sets in that job by issuing an ENQ for each of them, using the value specified for DISP to determine the kind of ENQ issued. The initiator issues the ENQ for each data set at the highest level required for that data set by any step of the job. For example, if all steps of the job request shared control of a specific data set (DISP=SHR) then the ENQ for that data set is requested as SHR. If, on the other hand, any step of the job requests exclusive control of a specific data set (DISP=NEW, DISP=MOD, or DISP=OLD), then the ENQ for that data set is requested EXCL.

The ENQ for each dataset is released at the end of the last step of the job referencing it. Since ENQs cannot be downgraded from EXCL to SHR, if one step needs the ENQ EXCL and a following step only needs it SHR, the ENQ is still issued as EXCL and held until the end of the last step which references that data set, at which point the ENQ is released entirely.


Wednesday, February 18, 2026

COBOL Binary search

We had a situation where we loaded a large VSAM file into memory to be searched by online CICS application. We encountered problems trying to emulate the VSAM START verb using COBOL SEARCH ALL verb when the key does not exist in the array. To get around this we had to write our own BINARY SEARCH in COBOL. 

The array which we are searching contains about 240,000 entries. 

We found that the hand coded BINARY SEARCH was significantly more efficient in terms of CPU usage than the COBOL "SEARCH ALL" verb. 

The code was modeled after KNUTH's binary search, see this link 

http://www.z390.org/contest/p21/P21DW1.TXT 

the key to maximizing the performance of the code below was to use PIC S9(8) COMP for all the binary fields. This avoids the check for binary overflow in the generated code. Also we used the compiler option TRUNC(OPT) to avoid the code generated to check for truncation. 

Note --> the IF statement after the PERFORM loop is to check for a "not found" condition. To emulate the VSAM START command we need to position the INDEX to the first row which is >= the search key. 


           MOVE +1                     TO BIN-LOW. 
           MOVE BCNTR-TCA1-ENTRIES-USED 
                                       TO BIN-HIGH. 

           PERFORM WITH TEST AFTER 
               UNTIL BIN-LOW > BIN-HIGH 
               COMPUTE BIN-RANGE = BIN-HIGH - BIN-LOW 
               COMPUTE BIN-MID = (BIN-RANGE / 2) + BIN-LOW 
               SET TCA1-INDEX          TO BIN-MID 
               EVALUATE TRUE 
                   WHEN TCA1-KEY (TCA1-INDEX) = SRCH-TCA1-KEY 
                       MOVE 1          TO BIN-RANGE 
                       COMPUTE BIN-LOW = BIN-HIGH + 1 
                   WHEN TCA1-KEY (TCA1-INDEX) < SRCH-TCA1-KEY 
                       COMPUTE BIN-LOW  = BIN-MID + 1 
                   WHEN OTHER 
                       COMPUTE BIN-HIGH  = BIN-MID - 1 
               END-EVALUATE 
           END-PERFORM. 


           IF TCA1-KEY (TCA1-INDEX) < SRCH-TCA1-KEY 
               SET TCA1-INDEX          UP BY +1 
           END-IF. 

Tuesday, February 10, 2026

Row-Value-Expression and Quantified Predicates in Db2

Row-Value-Expression in Db2

A row-value-expression allows you to compare multiple columns (or values) at once as a tuple. Instead of writing separate conditions for each column, you can group them together.

General Syntax

(COL1, COL2, COL3) operator (Value1, Value2, Value3)

·        Both sides must have the same number of values.

·        Data types must be compatible.

·        Comparisons are evaluated pair by pair.

·        If any comparison involves NULL, the result may be Unknown.

Operators Explained with Examples

1. Equality (=)

(COL1, COL2, COL3) = (100, 'X', 2000)

·       Row (100, 'X', 2000) → True

·       Row (100, 'Y', 2000) → False

·       Row (100, NULL, 2000) → Unknown

2. Inequality (<>)

(COL1, COL2, COL3) <> (100, 'B', 500)

·       Row (100, 'B', 500) → False (all equal)

·       Row (100, 'C', 500) → True (COL2 <> 'B')

·       Row (101, 'B', 500) → True (COL1 <> 100)

3. Less Than (<)

(COL1, COL2, COL3) < (100, 'B', 500)

·       Row (100, 'A', 500) → True ('A' < 'B')

·       Row (99, 'Z', 999) → True (99 < 100)

·       Row (100, 'B', 400) → True (400 < 500)

4. Greater Than (>)

(COL1, COL2, COL3) > (100, 'B', 500)

·       Row (100, 'C', 500) → True ('C' > 'B')

·       Row (101, 'A', 300) → True (101 > 100)

·       Row (100, 'B', 600) → True (600 > 500)

5. Less Than or Equal (<=)

(COL1, COL2, COL3) <= (100, 'B', 500)

·       Row (100, 'B', 500) → True (exact match)

·       Row (100, 'A', 500) → True ('A' < 'B')

·       Row (99, 'Z', 999) → True (99 < 100)

6. Greater Than or Equal (>=)

(COL1, COL2, COL3) >= (100, 'B', 500)

·       Row (100, 'B', 500) → True (exact match)

·       Row (100, 'C', 500) → True ('C' > 'B')

·       Row (101, 'A', 300) → True (101 > 100)

The detailed IBM manual can be found at the following link:

 https://www.ibm.com/docs/en/db2-for-zos/12.0.0?topic=predicates-basic-predicate#db2z_basicpredicate__fnocop

 

Quantified Predicates in Db2

A quantified predicate compares a value (or a row of values) against a set of values returned by a subquery (fullselect). It uses operators together with quantifiers like ALL, SOME, or ANY.

General Syntax

expression operator {ALL | SOME | ANY} (fullselect1)

(row-value-expression) operator {ALL | SOME | ANY} (fullselect2)

·       expression → single value compared against a column of values.

·       row-value-expression → tuple of values compared against multiple columns.

·       fullselect → subquery returning one or more values.

Behavior of Quantifiers

1. ALL

  • True if the relationship holds for every value returned by the subquery.
  • False if the relationship fails for at least one value.
  • Unknown if no comparison is false, but at least one is unknown due to NULL.
  • Special case: If the subquery returns no rows, the result is True.

2. SOME / ANY

  • True if the relationship holds for at least one value returned by the subquery.
  • False if the subquery is empty or the relationship fails for all values.
  • Unknown if no comparison is true, but at least one is unknown due to NULL.

Examples

TBLA


COLA

1

2

3

4

TBLB

 

COLB

COLC

2

2

3

TBLC


COLB

COLC

2

2


Example 1: ALL

COLA > ALL (SELECT COLB FROM TBLB UNION SELECT COLB FROM TBLC)

·       Subquery returns {2, 3}.

·       Predicate is False for rows 1, 2, 3.

·       True for row 4 (4 > 2 and 4 > 3).

Example 2: ANY

COLA > ANY (SELECT COLB FROM TBLB UNION SELECT COLB FROM TBLC)

·       Subquery returns {2, 3}.

·       Predicate is False for rows 1, 2.

·       True for rows 3, 4 (3 > 2, 4 > 2 or 3).

Example 3: ALL with NULL

COLA > ALL (SELECT COLC FROM TBLB UNION SELECT COLC FROM TBLC)

·       Subquery returns {2, NULL}.

·       Predicate is False for rows 1, 2.

·       Unknown for rows 3, 4 (because of NULL).

Example 4: SOME with NULL

COLA > SOME (SELECT COLC FROM TBLB UNION SELECT COLC FROM TBLC)

·       Subquery returns {2, NULL}.

·       Predicate is Unknown for rows 1, 2.

·       True for rows 3, 4 (3 > 2, 4 > 2).

Example 5: Empty Result with ALL

COLA < ALL (SELECT COLB FROM TBLB WHERE COLB > 3

            UNION

            SELECT COLB FROM TBLC WHERE COLB > 3)

·       Subquery returns empty set.

·       Predicate is True for all rows (special case).

Example 6: Empty Result with ANY

COLA < ANY (SELECT COLB FROM TBLB WHERE COLB > 3

            UNION

            SELECT COLB FROM TBLC WHERE COLB > 3)

·       Subquery returns empty set.

·       Predicate is False for all rows.


The detailed IBM manual can be found at the following link:

https://www.ibm.com/docs/en/db2-for-zos/12.0.0?topic=predicates-quantified-predicate