Showing posts with label z/OS. Show all posts
Showing posts with label z/OS. Show all posts

Saturday, July 31, 2021

How to concatenate all generations of a dataset?

 Hello πŸ‘‹

In this post, let's see πŸ‘€ how we can concatenate all the existing generations of a dataset. In z/OS, a dataset which have generations (each generation is a successive update) is called as Generation Data Group (abbreviated to GDG).

This picture is for the thumbnail of this blog post. 

When you have a job whose task is to reference all existing generations of a data set, you would normally need to manually check the generation numbers and insert them into the JCL. 

One way around this is to just code the GDG base entry name and the system will automatically pick up all cataloged generations. You don't have to manually check for the generation numbers πŸ’ƒ.

 

JCL to concatenate the GDG generations.

Upon submitting the JCL,

JESYSMSG Listing after the completion of the job.

It is evident in the output produced from this job that the latest generation of this data set is accessed first (LIFO) and so on. 

How the order of concatenations can be modified?

LIFO order can be reversed using the GDGORDER parameter. 

Usage of GDGORDER Parameter in the JCL.


Upon submitting the JCL,

You can now see that the order of concatenation has changed.

It's worth noting that by default, the generations are concatenated in Last In First Out order. GDGRODER comes handy when you want to override the default. 

Hope this helps!


Tuesday, May 11, 2021

Updating Sequential files using COBOL

There is no doubt Mainframes running COBOL powers majority of world's business transactions. Some of the firms are Financial institutions, hospitals, government and logistics.    

The very first site that I worked for is (even now) a global leader on the market of business information. They collect, store and process a business's information to generate credit scores and business information reports. The scores assess the business and it helps, say, a bank to use the information in the report when deciding to offer a loan to that business. 

Master file:

    I was part of the application which generated the scores. We stored the scores for ~80 million businesses and we didn't maintain a database. Rather, we used a sequential Master file which was inclined to grow whenever a new business's score was generated. 

In addition to that, it was necessary that we updated the scores of the existing businesses in daily basis as a business is prone to changes (there might be a change in CEO; the business might go Out of Business or Bankrupt; the business might win a Suit; trade payment changes undergone by the business and so on). 

The Master file had a key field (a unique number assigned for each business) which uniquely identified each record. 
All the records were in sequence by the key field. 
The Master file's width (LRECL) was large enough to accomodate every information collected about the business. 
There were coded fields (e.g., codes used for Bankruptcy status, Out of business status etc.) to save space.



Transaction file:

    Daily changes of the business were stored in a file referred to as transaction file. The transaction file had all transactions to be posted to the Master file that have occurred since the previous update. The transaction file also had a key field (the same key as that of the Master file) and all the records in the transaction file were in sequence by the key field.


Updating a Master file:

    The process of making the Master file current is referred to as updating. The Master file is updated via sequential processing by reading in the Master file along with the transaction file and creating a new master file. At the end of the update process, there will be an old master and a new master; should something happen to the new master file, it can be recreated from the old. Refer to the following picture for better clarity.

Click on the image for a larger version.


The Old Master file (OLD-MASTER) contains master information that was complete and current till the previous updating cycle. The transaction file (TRANS-FILE) contains transactions or changes that occurred since the previous updating cycle. These transactions or changes must be incorporated into the master file to make it current and updated. As a result, a New Master file (NEW-MASTER) will include all OLD-MASTER data in addition to the changes stored on the TRANS-FILE that have occurred since the last update. 

As all the records are in sequence by the key field, we compare the key field in the Old Master file to the same key field in the transaction file to determine if the master record is to be updated; this comparison requires both the files to be in sequence by the key field.  

Let's take a look at the format of the two input files:

OLD-MASTER πŸ“‚ 

(in sequence by M-BUSINESS-NO)

COLS        FIELD

1-9             M-BUSINESS-NO

10-39      M-BUSINESS-NAME

40-42      M-SCORE

43-100       M-FILLER


TRANS-FILE πŸ“‚

(in sequence by T-BUSINESS-NO)

COLS        FIELD

1-9             T-BUSINESS-NO

10-39      T-BUSINESS-NAME

40-42      T-SCORE

43-100       T-FILLER


How input transaction and Master records are processed?

Once all the files are opened, a record is read from both the Old Master file and the transaction file. As the files are already in sequence by their respective key fields, a comparison of M-BUSINESS-NO and T-BUSINESS-NO should be made to determine the next set of actions. Three possible conditions are met when comparing M-BUSINESS-NO and T-BUSINESS-NO fields: 

IF T-BUSINESS-NO = M-BUSINESS-NO

If the business numbers are equal, this means that a transaction record exists with the same business number as that on the Master file. When this condition is met, the transaction data is posted to the master record. This means, the record which goes into the New Master file will contain the updated score and other fields from the transaction file.

Once the record is written, the next record is read from both the Old Master file and Transaction file. 

IF T-BUSINESS-NO > M-BUSINESS-NO 

If T-BUSINESS-NO IS > M-BUSINESS-NO, this means that M-BUSINESS-NO < T-BUSINESS-NO. In this case, there is a record in the Master file with a business number less than the business number on the transaction file. Since both the files are in sequence by the business number, this condition means that a master record exists for which there is no corresponding transaction record. This means, the record read from the master file hasn't gone through any changes during the current update cycle and should be written as it is onto the New Master file.

Once write is made to the New Master file, next record is read only from the Old Master File. We do not read another record from the Transaction file as we haven't processed the last transaction record that caused T-BUSINESS-NO to compare greater than M-BUSINESS-NO of the OLD-MASTER.

IF T-BUSINESS-NO < M-BUSINESS-NO

Since both the files are in sequence by business number, this condition would mean that a transaction record exists for which there is no corresponding record in the Master file. This could mean that the scores are generated for a new business (voila! πŸ˜ƒ). In this instance, a new master record is created entirely from the transaction file and is written onto the New Master file. 

Once written, the next record is read only from the Transaction file. We do not read another record from the Old Master file since we haven't processed the Master record that compared greater than T-BUSINESS-NO

The following example illustrates the update procedure along with the corresponding action to be taken:



A sample update program is shown below: (Language - COBOL)

  ID DIVISION.                     
  PROGRAM-ID. CBL4.                  
  AUTHOR. SRINIVASAN.                 
 *                           
  ENVIRONMENT DIVISION.                
  INPUT-OUTPUT SECTION.                
  FILE-CONTROL.                    
    SELECT OLD-MASTER ASSIGN TO OLDMAST.       
    SELECT NEW-MASTER ASSIGN TO NEWMAST.       
    SELECT TRANS-FILE ASSIGN TO TRANS.        
 *                           
  DATA DIVISION.                    
  FILE SECTION.                    
  FD OLD-MASTER                    
    RECORDING MODE IS F               
    RECORD CONTAINS 100.               
  01 OLD-MASTER-REC.                  
   05 M-BUSINESS-NO        PIC X(9).     
   05 M-BUSINESS-NAME      PIC X(30).    
   05 M-SCORE              PIC 9(3).     
   05 M-FILLER             PIC X(58).    
  FD TRANS-FILE                    
    RECORDING MODE IS F               
    RECORD CONTAINS 100.               
  01 TRANS-REC.                    
   05 T-BUSINESS-NO        PIC X(9).     
   05 T-BUSINESS-NAME      PIC X(30).    
   05 T-SCORE              PIC 9(3).     
   05 T-FILLER             PIC X(58).    
  FD NEW-MASTER                    
    RECORDING MODE IS F               
    RECORD CONTAINS 100.               
  01 NEW-MASTER-REC.                  
   05 N-BUSINESS-NO        PIC X(9).     
   05 N-BUSINESS-NAME      PIC X(30).  
   05 N-SCORE              PIC 9(3).   
   05 N-FILLER             PIC X(58).  
 *                         
  PROCEDURE DIVISION.               
  100-MAIN-MODULE.                 
      PERFORM 800-INITIALIZATION-RTN        
      PERFORM 600-READ-MASTER           
      PERFORM 700-READ-TRANS            
      PERFORM 200-COMPARE-RTN           
        UNTIL M-BUSINESS-NO = HIGH-VALUES    
          AND T-BUSINESS-NO = HIGH-VALUES    
      PERFORM 900-CLOSE-FILES-RTN         
      STOP RUN.                  
 *                         
  200-COMPARE-RTN.                 
      EVALUATE TRUE                
      WHEN T-BUSINESS-NO = M-BUSINESS-NO      
           PERFORM 300-REGULAR-UPDATE       
      WHEN T-BUSINESS-NO < M-BUSINESS-NO      
           PERFORM 400-NEW-ACCOUNT         
      WHEN OTHER                  
           PERFORM 500-NO-UPDATE          
      END-EVALUATE.                
 *                         
  300-REGULAR-UPDATE.               
      MOVE OLD-MASTER-REC TO NEW-MASTER-REC    
      WRITE NEW-MASTER-REC             
      PERFORM 600-READ-MASTER           
      PERFORM 700-READ-TRANS.           
 *                         
  400-NEW-ACCOUNT.                 
      MOVE SPACES TO NEW-MASTER-REC        
      MOVE T-BUSINESS-NO TO N-BUSINESS-NO     
      MOVE T-BUSINESS-NAME TO N-BUSINESS-NAME   
      MOVE T-SCORE TO N-SCORE            
      MOVE T-FILLER TO N-FILLER           
      WRITE NEW-MASTER-REC              
      PERFORM 700-READ-TRANS.            
 *                          
  500-NO-UPDATE.                   
      WRITE NEW-MASTER-REC FROM OLD-MASTER-REC    
      PERFORM 600-READ-MASTER.            
 *                          
  600-READ-MASTER.                  
      READ OLD-MASTER                
      AT END MOVE HIGH-VALUES TO M-BUSINESS-NO    
      END-READ.                   
 *                          
  700-READ-TRANS.                  
      READ TRANS-FILE                
      AT END MOVE HIGH-VALUES TO T-BUSINESS-NO    
      END-READ.                   
 *                          
  800-INITIALIZATION-RTN.              
      OPEN INPUT OLD-MASTER             
                 TRANS-FILE             
          OUTPUT NEW-MASTER.             
 *                          
  900-CLOSE-FILES-RTN.                
      CLOSE OLD-MASTER                
            TRANS-FILE                
            NEW-MASTER.               
 *                          
Two  files (Old Master file and Transaction file) are passed as input to the COBOL program. The program creates the New Master file as output.  Contents of the files are shown below:

Old Master file:
Contents of Old Master file.


Transaction file:
Contents of Transaction file


JCL used to compile and run the load module:
First step of the JCL compiles the COBOL program. If the compilation is successful, the second step will run to execute the load. 


After submitting the JCL, the following output file is created. 

New Master file:
Contents of New Master file.

Note the new record with business number as 000000004 added to the New Master file. Also, the scores of the existing businesses are updated. 

Use of HIGH-VALUES for End of file conditions:

With 2 input files, it's very unlikely that both the files will reach AT END conditions at the same time. There are high chances that the transaction file will run out of records before the Old Master file. In such cases, the remaining records from the Old Master file must be written to the New Master file. 

The COBOL reserved keyword, HIGH-VALUES is moved to the business number fields when the Old Master file/Transaction file has reached its end. 

HIGH-VALUES refer to the largest value in the system's collating sequence. This is a character consisting of "all bits on" in a single storage position. All bits on in EBCDIC represents a nonstandard, nonprintable character used to specify the highest value in the system's collating sequence. 

When the Transaction file reaches the end, HIGH-VALUES are moved to T-BUSINESS-NO. This ensures that the subsequent attempt to compare the T-BUSINESS-NO and M-BUSINESS-NO will always result in a "greater than" condition i.e., there is a record in the Master file with a business number less than the business number on the transaction file. This means the record read from the master file hasn't gone through any changes during the current update cycle and should be written as it is onto the New Master file.

HIGH-VALUES is a figurative constant that may be used only with fields that are defined as alphanumeric. If numeric fields are used, then moving all 9s (999999999) to the key field will always compare higher than any other number. Beware; if a business number of 999999999 is a possible entry, then moving all 9s during end-of-file condition could produce error. 

We've hit the end-of-file condition for this blog post πŸ˜‰

    In this post, we learnt about the procedure used for updating sequential files in COBOL. This procedure is also referred to as 'file-matching logic'. Hope it was useful. 

    In the next post, I'll try to implement the same stuff but in Python. Thanks for reading! Should you have any queries/suggestions, please post it in the Comments section below πŸ‘.


References used for this post:
Structured COBOL Programming - 8th Edition - Stern/Stern.



Wednesday, May 5, 2021

Using process statements in SuperCE utility

One of the item that I always strike off ✅ from my checklist whenever I'm assigned with a task of modifying an existing code is Source Code Comparison. It allows me to highlight the difference between different versions of the code. It also acts as a proof for the reviewer that only the intended parts of the code were modified. 

Although, CA Endevor lets us use the Changes (C) option to look at the actual lines we've changed, I rely upon SuperCE utility (option 3.13) to compare the modified code and the existing version of the code in Production environment. 

Welcome to my blog! πŸ˜€ In this blog post, we will look at the SuperCE (option 3.13) ISPF option - which is used to compare the content of two datasets - and the usage of Process statements which is similar to the usage of control statements in IBM's DFSORT utility. 

This one is for the Thumbnail 😁

Your time is precious. So, please use the following links to navigate to different sections of this post. 


Intro

SuperC (I guess the suffix 'C' after Super stands for Compare) is the standard option to compare two datasets of unlimited size and record length. SuperCE is the extended version of the standard SuperC Utility and it offers more flexibility like,

  • Comparing the datasets in line, word or byte level, 
  • Supplying process statements for specific compare requirements 
  • Various listing types and so on. 

How to access SuperCE Utility and use it?

To access the SuperCE Utility from ISPF Primary Option Menu, type 3 (Utilities) and press Enter.

Click on the image for a larger version.

ISPF Primary Option Menu.


From the Utility Selection Panel, type 13 (SuperCE)  and press Enter

Selecting SuperCE from Utility Selection Panel.


Voila! πŸ‘
SuperCE Utility Panel.

Alternatively, you can type =3.13 from ISPF Primary Option Menu (or command line for that matter) and hit Enter to directly get into SuperCE Utility panel.
 

How to use SuperCE Utility?

Now that we're inside the SuperCE Utility panel, let's use it. 
The true method of knowledge is experiment. 
 - William Blake
To use SuperCE utility, we should have two datasets. It can be a sequential dataset, PDS or a member inside a PDS. ❗ SuperC and SuperCE doesn't support tape datasets. 

I've got 2 PDS members with a simple COBOL program in each of them. For better understanding, I've named these members as NEW and OLD because the contents in the NEW member is an updated version of contents in OLD member.

The NEW member. This COBOL program accepts a name from the user and displays the name with a greet. 


The OLD member. As you probably know, this COBOL program simply displays a very famous message to the user. 


The next step is to input these datasets in the SuperCE Utility panel and do the comparison. The New DS Name field should be provided with the updated version of the dataset that you want to compare and the Old DS Name field should be provided with the previous version of the dataset. 

Using the SuperCE Utility panel.

Whenever you access the SuperCE Utility panel, it provides default setting for the Compare Type, Listing Type, Listing DSN, and Browse option. 

SuperCE Utility works the best for you with the following settings,
  • Compare Type - Line (Compares the dataset for line differences)
  • Listing Type - Delta (SuperCE provides a listing after the comparison. This listing shows some awesome stats. Delta option lists the differences between the source data sets, followed by the general summary)
  • Listing DSN - This is where the listing output will be stored. SuperCE allocates a default DSN in case if you leave this field blank. If you want to store the results of comparison (I do, as I used to pass on this dataset to my code reviewer), you may provide your own DSN.  
  • Display Output - Yes (This option tells ISPF that you want the output listing to be displayed. If you choose the option No, SuperCE will not show the listing but it shows the result of the comparison (Differences found or No differences found) at the top right corner of the panel). 
  • Output Mode - View or Browse 
  • Execution Mode - Foreground is the default. 
For more details about the SuperCE Panel Fields, click πŸ‘‰ here.  

Let's hit Enter to allow SuperCE perform the comparison. The listing output after the comparison is shown below.
 
Listing output for Line Compare. 

In the Listing Output Section (Line #4 thru 21), the source lines are shown. 

Left side of each line is either marked with I (Insert) or D (Delete). 

The first source line at line #9, 000200 PROGRAM-ID. NEW.  , is marked with I (Insert) i.e., the listing tells that this line was inserted in the New DSN and wasn't found in the Old DSN. 

The next source line at line #10 is marked with D (Delete) i.e., the listing tells that this line is present in Old DSN but not in the New DSN. So, it must have been deleted in the updated version of the code. 

The Line Compare Summary and Statistics section at the bottom shows the overall summary of the comparison. 

How to use process statements to perform diverse data comparisons?

As you would've noticed in the listing output, the first 6 bytes (Column Numbers) of the COBOL code was also included for the comparison by SuperCE. 

Suppose you want to compare data residing in the columns 7 thru 72 in both the datasets, you should supply process statements for this requirement. 

The process statements panel can be accessed by typing E in the command line of SuperCE Utility panel, or by using Options action bar choice and choosing Option 1 - Edit Statements.

Accessing Process Statements panel.


In the following picture, some examples of the statements that can be used are shown in the bottom half of the screen. The actual statements required for your comparison should be typed in the EDIT window shown in the first half of the screen. 

Process Statements panel.


CMPCOLM process statement should be used to compare using a column range.

Inputting Process Statements. 

We can exit the screen now by pressing F3. A message, 'Statements DS saved' is displayed at the top right corner of the SuperCE Utility panel. 

Statements DS Saved.


The compare statements will be stored in the dataset provided in Statements DSN field in SuperCE Utility panel. This field can also be left blank allowing the system to create one dataset for you to store the process statements. 

On hitting Enter, the compare request will be invoked with the process options.
 
Listing Output

The Line Compare Summary shows that there are 4 line matches and 6 differences. At the bottom of the screen, the criteria used for this compare task is specified. 

There are many flavours of process statements that can be invoked depending on what you need to compare. Some of them are listed below. 

Example 1:



You can notice that the end of the process statement, CMPCOLM, contains a suffix of N and O, indicating that it is referencing the New DSN and Old DSN respectively. What follows the statement is the column range within the referenced dataset. 

With these statements, we tell SuperCE that we want to compare the data residing in columns 5 to 30 in the New DSN with data in columns 1 to 25 in the Old DSN. 

Example 2:
Suppose you want to ignore the comment lines in your COBOL code from being compared. 



DPLINE (Do not process lines) process statement do not process the lines that can be recognized by a unique character string, for comparison. 

DPLINE '*',7 scans for an asterisk ('*') in column 7 and ignores it from being compared.


Example 3:
Suppose if you want to compare only specific rows in each datasets.


The NFOCUS and OFOCUS process statements can be used to specify the rows to be used for the comparison. In this case, rows 1 thru 10 will be used from the New DSN while rows 11 thru 21 will be used from the Old DSN. 

More about Process Statements can be found πŸ‘‰ here

Running SuperCE in batch mode

Sit back and relax. You can create a JCL from SuperCE Utility panel (with fewer hits on that Enter button) to run the comparison in batch mode. ISRSUPC is the program which is used for comparison.

After providing the datasets in the New and Old DSN, select the execution mode as Batch and press Enter. In the Submit Batch jobs panel, Job statement info is provided at the bottom of the screen. I've chose to Edit JCL before submit. 

SuperC Utility - Submit Batch jobs panel.


Upon hitting Enter, the JCL is shown to user. 



If you are adding Process Statements, a SYSIN DD statement will be added to the JCL. 



Conclusion

Hope you witnessed the uses of SuperCE utility. If SuperCE stands for Super Compare Extended, then adjective Super is well suited and appropriate. Should you have any questions/suggestions please leave it in the comments section below. Thx πŸ‘


References: 
  • z/OS ISPF User's Guide Vol II
  • TSO/ISPF Curriculum z/OS v2.3 - Interskill Learning


Sunday, April 25, 2021

Everything about IEFBR14 utility

It takes one full blog post to list out (almost) everything that can be done using a utility which is widely known as a program that does nothing. Ironic! πŸ˜€

Yup! I'm talking about IBM's IEFBR14 utility. 



Table of Contents πŸ“š

Use the links given below to navigate to various sections of this post.

Introduction 

When IEFBR14 is invoked, it branches to the address in Register 14, which returns back control to the operating system. The Assembler instruction to do this is BR 14. That's how this utility got the name as IEFBR14.

When IEFBR14 is called, it immediately returns back the control to the operating system with a completion code of 0. By returning the control to z/OS, IEFBR14 allows the system to process the disposition parameter on any DD statements that are specified along with the EXEC statement. We're simply exploiting this functionality of IEFBR14 for the creation and deletion of datasets. 

IEFBR14 was created because while DD statements can create or delete files easily, they cannot do so without a program to be run due to a certain peculiarity of the Job Management system, which always requires that the Initiator actually execute a program, even if that program is effectively a null statement. The program used in the JCL does not actually need to use the files to cause their creation or deletion — the DD DISP=... specification does all the work. Thus a very simple do-nothing program was needed to fill that role.
- Quoted text from Wikipedia.

Using IEFBR14 utility to create and delete datasets 


IEFBR14 is typically used for creating and deleting datasets. A sample JCL is shown below. 
 ****** ***************************** Top of Data ******************************  
 000001 //Z01071A JOB 1,NOTIFY=&SYSUID                       
 000002 //*                                     
 000003 //STEP1  EXEC PGM=IEFBR14                         
 000004 //DEL01  DD DSN=Z01071.PS.A,                       
 000005 //     DISP=(MOD,DELETE,DELETE),                    
 000006 //     SPACE=(CYL,(1,0),RLSE)                      
 000007 //NEW01  DD DSN=Z01071.PS.B,                       
 000008 //     DISP=(NEW,CATLG,DELETE),                     
 000009 //     SPACE=(CYL,(1,0),RLSE),                     
 000010 //     DCB=(LRECL=80,RECFM=FB,BLKSIZE=800)                                         
 ****** **************************** Bottom of Data ****************************  
IEFBR14 job step usually consists of an EXEC statement and DD statement for each dataset that we want to process.

As datasets are being referenced in each DD statement, a DISP parameter SHOULD be accompanied. 

Creation of datasets can also be done in foreground mode - 3.2 Data Set Utility panel - from ISPF. IEFBR14 utility is used when we want to create or delete the datasets as part of batch run.  

Creating a dataset using IEFBR14 utility


The JCL to create a new dataset using IEFBR14 utility is as follows: 
 ****** ***************************** Top of Data ******************************  
 000001 //Z01071A JOB 1,NOTIFY=&SYSUID                       
 000002 //*                                     
 000003 //STEP1  EXEC PGM=IEFBR14                         
 000004 //NEW01  DD DSN=Z01071.NEW.DATASET,                    
 000005 //     DISP=(NEW,CATLG,DELETE),                     
 000006 //     SPACE=(CYL,(1,0),RLSE),                     
 000007 //     DCB=(LRECL=80,RECFM=FB,BLKSIZE=800)                                          
 ****** **************************** Bottom of Data ****************************  

The DD statement named as NEW01 creates a new, empty dataset called Z01071.NEW.DATASET. All the information necessary to create the dataset has been provided in the JCL. 

DISP=(NEW,CATLG,DELETE) - creates a new dataset and catalogs it under normal termination. The dataset will be deleted if the job is terminated abnormally.

BLKSIZE of 800 is provided because the dataset created when providing BLKSIZE=0 may not be opened for view/edit as the system issues 'Invalid block size' message.

Click on the image for a larger version.

System issues 'Invalid block size' message when the dataset is created with BLKSIZE=0.

What happens when you try to create a dataset using IEFBR14 utility but without providing a DCB parameter in the DD statement πŸ€”?


The dataset gets created but it's not usable. Let's look at the dataset information.
 
Data Set Information shows the record format as ?, Record length and Block Size as 0.


Deleting a dataset using IEFBR14 utility


The JCL to delete an existing dataset before its creation is as follows: 

 ****** ***************************** Top of Data ******************************  
 000001 //Z01071A JOB 1,NOTIFY=&SYSUID                       
 000002 //*                                     
 000003 //STEP1  EXEC PGM=IEFBR14                         
 000004 //DEL01  DD DSN=Z01071.PS.A,                       
 000005 //     DISP=(MOD,DELETE,DELETE),                    
 000006 //     SPACE=(CYL,(1,0),RLSE)                      
 ****** **************************** Bottom of Data ****************************  

The DD statement named as DEL01 deletes an existing dataset. If the dataset doesn't exist, MOD disposition creates the dataset and deletes it. Hence, SPACE parameter is provided. 

πŸ’£The job will fail with JCL error if the DD statement has got a DISP=(MOD,DELETE,DELETE) without SPACE= parameter and the dataset doesn't exist. 

SPACE= parameter may not be necessary if you're trying to delete an already existing dataset with DISP=(MOD,DELETE,DELETE).

DISP=(OLD,DELETE,DELETE) without a SPACE= parameter can also be coded if you're pretty sure about the existence of a dataset before running the utility job to delete and re-create the dataset.

What happens when you provide a GDG base in IEFBR14 utility with DISP=(MOD,DELETE,DELETE) πŸ€”?

Let's try this out!

I've created a GDG base named Z01071.TEST.GDG with 3 generations.  


The JCL is as follows:

 ****** ***************************** Top of Data ******************************  
 000001 //Z01071A JOB 1,NOTIFY=&SYSUID                       
 000002 //*                                     
 000003 //STEP1  EXEC PGM=IEFBR14                         
 000004 //DEL01  DD DSN=Z01071.TEST.GDG,                     
 000005 //     DISP=(MOD,DELETE,DELETE)                     
 ****** **************************** Bottom of Data ****************************  

The JESYSMSG listing after the completion of the job is shown below.



Just the generations that are part of the GDG base gets deleted; not the GDG base itself. 

πŸ’‘ If you want to delete the GDG base in batch run, IDCAMS utility with DELETE command can be used. 

What happens when you provide a PDS member in IEFBR14 utility with DISP=(MOD,DELETE,DELETE) πŸ€”?

Let's experiment!

I've created a PDS named Z01071.TEST.PDS with 3 members in it. 


Let's try to delete the first member (MEMBER1) using the following JCL. 
 ****** ***************************** Top of Data ******************************  
 000001 //Z01071A JOB 1,NOTIFY=&SYSUID                       
 000002 //*                                     
 000003 //STEP1  EXEC PGM=IEFBR14                         
 000004 //UNCAT01 DD DSN=Z01071.TEST.PDS(MEMBER1),                 
 000005 //     DISP=(MOD,DELETE,DELETE)                     
 ****** **************************** Bottom of Data ****************************  

The results are pretty surprising. Thank god, I didn't store anything important in the test PDS πŸ˜€.


The entire PDS is deleted. 

Uncataloging a dataset using IEFBR14 utility

There is a difference between uncataloging a dataset and deleting a dataset. 

When a dataset is uncataloged, it's removed from the catalog so that if you search for the dataset from the Data Set List Utility (=3.4) just by providing the dataset's name, you will not be able to find the dataset. You should also provide the Volume Serial number the dataset is residing upon.
 
Whereas, if a dataset is deleted, it's removed from VTOC (Volume Table of Contents) and the dataset may not be retrieved.   

Remember that both SMS and non-SMS data sets can be created and deleted using IEFBR14 utility. Only non-SMS data sets can be cataloged and uncataloged.

Let's try to uncatalog a dataset using IEFBR14 and the JCL is as follows: 

 ****** ***************************** Top of Data ******************************  
 000001 //Z01071A JOB 1,NOTIFY=&SYSUID                       
 000002 //*                                     
 000003 //STEP1  EXEC PGM=IEFBR14                         
 000004 //UNCAT01 DD DSN=Z01071.INPUT.PS.A,                    
 000005 //     DISP=(OLD,UNCATLG)                        
 ****** **************************** Bottom of Data ****************************  
The JESYSMSG listing after the completion of the job is shown below.

Z01071.INPUT.PS.A dataset is uncataloged. 

Now that the dataset is uncataloged, let's try to search for the dataset just by providing the dataset's name. 
When we try to search for the dataset just by providing its name, No data set names found.

When we provide the Data set name as well as Volume Serial no., the dataset is listed. 



To catalog the dataset using IEFBR14 utility, the following JCL can be used. 
 ****** ***************************** Top of Data ******************************  
 000001 //Z01071A JOB 1,NOTIFY=&SYSUID                       
 000002 //*                                     
 000003 //STEP1  EXEC PGM=IEFBR14                         
 000004 //UNCAT01 DD DSN=Z01071.INPUT.PS.A,                    
 000005 //     DISP=(OLD,CATLG),                        
 000006 //     UNIT=3390,                            
 000007 //     VOL=SER=VPWRKB                          
 ****** **************************** Bottom of Data ****************************  
Note: The UNIT and VOL=SER= parameters must be provided to catalog a dataset.

Running an IEFBR14 JCL using Zowe CLI

Let's put everything (creating, deleting, cataloging and uncataloging) together in a JCL, store it as a local file (.txt file) in Desktop and try to invoke the local file using Zowe CLI (Command Line Interface).

Prerequisites:
  • Access to Zowe and z/OS MF (I've used the access obtained as part of Master the Mainframe 2020). 
  • Zowe CLI must be installed on the system (For additional Zowe CLI documentation, visit https://docs.zowe.org)
Let's create a text file with the following contents. 
 //Z01071A JOB 1,NOTIFY=&SYSUID        
 //*                      
 //STEP1  EXEC PGM=IEFBR14          
 //DEL01  DD DSN=Z01071.PS.A,         
 //     DISP=(MOD,DELETE,DELETE)      
 //UNCAT01 DD DSN=Z01071.INPUT.PS.A,      
 //     DISP=(OLD,UNCATLG)         
 //DEL02  DD DSN=Z01071.TEST.GDG,       
 //     DISP=(MOD,DELETE,DELETE)      
 //DEL03  DD DSN=Z01071.TEST.PDS(MEMBER1),  
 //     DISP=(MOD,DELETE,DELETE)   
The file is saved on my Desktop and it's named as IEFBR14.txt.
Zowe CLI is installed on your own computer, not on the mainframe. You'll use Zowe CLI to interface with Zowe and z/OSMF which is running on the mainframe. 


Steps to submit a JCL stored in a .txt file using Zowe CLI  are as follows: 

1. Open Command Prompt and type zowe. You'll get back a description, a listing of command groups, and options. 

Using the Zowe CLI. 

2. We have to use zos-jobs group to submit a JCL. Type zowe zos-jobs --help-examples  to view some examples. 

3. To submit a JCL from a local file, we should use the command, 

zowe zos-jobs submit local-file "IEFBR14.txt".

Upon the submission of the command, a status bar is shown submitting the local file to z/OS. 


Zowe CLI shows the JobID and the Jobname of the submitted job.

Let's use the JobID to locate the job from Zowe Explorer plug-in in VS Code. 

The JOBS Section on the left side bottom of the picture shows that the job with JobID as JOB04256 completed with return code 0. The JESYSMSG is opened on the right side using the Z Open Editor plug-in.  

Conclusion

Throughout this post, you have witnessed the uses of IEFBR14 utility. Most of the JCL's given in this post were commonly used on the sites that I've worked so far. If I had missed anything, please let me know through the Comments section below. Thx πŸ‘


Wednesday, March 24, 2021

Printing the pattern of letters from A to Z using the respective letter itself

Hiya! Hope 🀞 this blog post will be fun πŸ˜€ as I really enjoyed writing this particular code which you will be witnessing shortly. 

When I saw the black screens πŸ’» for the first time when I was trained on Mainframe (that was in 2014 πŸ“…), I was totally amused.  The logon screen had something similar to what we have got now on the logon screen of IBM's Master the Mainframe 2020 system.

Click on the image for a larger version.

Each letter's shape in the string 'z/OS' is printed using the same letter, that too in Italics. 

Intro

I was longing to write a COBOL program which would print the ASCII character strings (just the letters A-Z for now) in large size to the output, using the respective letter itself (sometimes people prefer asterisk '*' or '#' to print shapes). This blog post is all about the approach I took to come up with such a program. 

At the end of this post, there's a short write-up on publishing a code on GitHub as I'm used to Endevor and GitHub (a code hosting platform) is new to me. 

Approach

Printing just one letter's shape in the output is simple. All you need is a PERFORM VARYING loop in COBOL, a logic to form the letter's shape and a DISPLAY statement printing the lines for each iteration of the loop. An example can be found πŸ‘‰ here.  

However, printing each letter's shape, of the string, from left to right is little bit tricky. I chose 7 x 7 cell to spread out the shape of each letter. An excel sheet, in which I drew all the 26 letter's shapes, came in handy as I referred the sheet before going to code the logic for each letter. 

An excel sheet with each alphabet's pattern spread out in a 7 x 7 cell.

I leveraged the two-dimensional table, to store the letter's shape. The COBOL code is as follows:


WS-LINE is an element of one-dimensional table that occurs 7 times. Assume each element of WS-LINE as a row.
 
WS-LETTER is an element of a two-dimensional table that occurs 70 times in each occurence of WS-LINE. Assume each element of WS-LETTER as a column. 

For readability, I've limited the maximum length of the string, input by the user, to 10 bytes. Hence, each line is 70 bytes long. 

When I was halfway with my code, I ran πŸƒ some tests only to realize that a space in between each letter's shape would be clear enough to read. 

That isn't easy to read. BAD πŸ™ˆ


Hence, I came up with yet another multi-dimensional table solely for printing purpose. 


This table gets data from the former 2D table (which we've already seen before) only at the point of displaying the entire stuff. 

In the PROCEDURE DIVISION, there are references to 3 para's,
  1. which would ask for the input string from the user; validate it. Upon successful validation of user input (read the next item),
  2. go through each letter of the string one by one with help of Reference Modification in COBOL; call the para corresponding to each letter - to print its shape - with the help of EVALUATE verb.
  3. display output and STOP RUN.
There are 26 para's coded to print the shape of 26 alphabets in English. A lot of PERFORM VARYING loops and COMPUTE statements are used to build 🧱 the logic in each para. Let's look at the code for one of those para.


This πŸ‘† part of code prints the shape of letter T. There are 2 PERFORM VARYING loops ➿. 
Let's look at the first loop ➰. 
  • The first loop iterates for 7 times with WS-J data item's value ranging from 0 to 6 and forms the horizontal line of letter T's shape.
  • WS-I data item holds the position of the letter in the string entered by the user. WS-I data item's value is multiplied with 7 to put the letter's shape in the right set of rows and columns. 
  • COMPUTE statement is coded before the MOVE statement because arithmetic expressions aren't supported (on IBM Enterprise COBOL for z/OS  6.3.0 compiler) in the subscripting.
  • The MOVE statement moves the letter T to WS-LETTER which is an element of two-dimensional table. In a two-dimensional table, the two subscripts correspond to the row and column numbers.
Given the following 7x7 cell:



The following happens in each iteration of the first loop, if WS-I's value is assumed as 1:

1st iteration:
WS-I = 1
WS-J = 0
WS-TEMP = 7
Letter T is moved to WS-LETTER(1, 7)

2nd iteration:
WS-I = 1
WS-J = 1
WS-TEMP = 6
Letter T is moved to WS-LETTER(1, 6)

3rd iteration:
WS-I = 1
WS-J = 2
WS-TEMP = 5
Letter T is moved to WS-LETTER(1, 5)

4th iteration:
WS-I = 1
WS-J = 3
WS-TEMP = 4
Letter T is moved to WS-LETTER(1, 4)

5th iteration:
WS-I = 1
WS-J = 4
WS-TEMP = 3
Letter T is moved to WS-LETTER(1, 3)

6th iteration:
WS-I = 1
WS-J = 5
WS-TEMP = 2
Letter T is moved to WS-LETTER(1, 2)

7th iteration:
WS-I = 1
WS-J = 6
WS-TEMP = 1
Letter T is moved to WS-LETTER(1, 1)

At the end of first loop, the cell will look like below:


The second loop does something similar to the first loop and it moves the letter to all the rows in 4th column of 7x7 cell. At the end of second loop, the shape of letter will be formed. 



Executing the code..

The full code is available πŸ‘‰ here in JDOODLE, an online compiler and editor for many programming langauges including COBOL. 

The COBOL program that I've written mimics the functionality of Banner command in Linux.

After clicking on the link, just scroll to the bottom of the code and give a string, max. of 10 characters, in Stdin Inputs and click Execute button in the blue box. After the execution, the result will be displayed in the Result area (black colored rectangle box). 

Output after running the code in JDOODLE.

Please note the following before providing input in Stdin Inputs tab:
  • Numbers and symbols like hyphen (-), dollar ($) etc., aren't supposed to be entered. The program code is hardwired with logics to form shapes only for the 26 alphabets (in upper-case). If numbers and symbols are part of the string, they will be replaced with spaces. 
  • I've used an intrinsic function (FUNCTION UPPER-CASE) to convert any string entered by the user to upper-case.
  • Please limit the input string to a maximum of 10 characters. String with length beyond 10 will be truncated.
  • If there are spaces in between the string, user will be prompted to re-enter another string without spaces in between. 
Stdin Inputs has got 3 lines of input string; first 2 lines has got strings with a space in between. Note the messages in the Result area.


Scope for improvement

  • Improvements can be made to the existing code to shorten the total number of lines.
  • Logics for lower-case alphabets, numbers and symbols can be added.
  • Length of the string, input by the user can be extended. 
  • The height and width of the cell is fixed for now and can be made scalable by altering the code.

GitHub

GitHub hosts millions of projects written in different programming languages. Each project is placed in its own container called a repository (repo) that can store code and other files of the project. Any changes to the files within a repo will be tracked via version control.

Each repo has got a name. There can be lots of repositories with same name. Hence, it's always better to use a link to locate the repo you're looking for. 

Go ahead and open this πŸ‘‰ repo I've created for this project. 

By default, this repository which I've created has got only one branch named main. Having the code in main branch is similar to having the code in the Production stage of  CA Endevor, a source code management tool for z/OS. 

If you want to do some edits on the code, you take a copy of the code residing in the Production stage of CA Endevor to your personal PDS. Likewise, in GitHub we use branches to make edits before commiting them to main. When a new branch is created, a new copy or snapshot of main is made.

There are 2 files in the main branch of the repository I've created for this project. A README file - which describes the project -  and a file named CBL1 which has got the COBOL program. 

All you need is an account on GitHub to create new branch for yourself in order to suggest edits/improvements for the code. commit by saving your changes. Open a pull request to propose your changes and request someone to review by using GitHub's @mention system. pull requests are merged  to the main branch when the new changes are reviewed and are good to go πŸ‘ .


That's it for now! πŸ”š

Hope you liked this post. Should you have any questions/suggestions, please post it in the comments section below.

ThxπŸ‘!