Friday, November 9, 2012

A quick guide for JCL



Job Control Language (JCL)

JCL controls how your programs are run on the mainframe. JCL is essentially an interface between your program and the operating system. It makes your programs more flexible, because you can specify options, such as dataset names, without the need to hardcode them in a program. You can easily change dataset names and specify parameters without needing to change and re-compile your program.
 The JCL tells the computer which program to run, where the program is located, which datasets to use and where to direct output.


General


Each line of JCL starts with two slashes ('//') in columns 1 to 2.
Columns 1 to 71 can be used to code JCL statements.
The JCL specifies a jobname and can contain one or more steps. Each step will execute a program.
Comments can be added to the JCL using //* in columns 1 to 3.
Every job will begin with a 'Job Card', which specifies the jobname, and other important information about how the job will execute.
The JCL is terminated using '//' in columns 1 and 2, or when there are no more statements to be read in.
 You can contuinue a statement parameters over several lines to make it more readable.
 

Some Terminology.
Dataset = Any type of file.
 Partitioned Dataset (PDS) = A special type of dataset which is split up into different members. Each 'member' of a PDS can contain, for example, a different program, or a piece of JCL. Also refered to as a library.
TSO = Time Share Option. An IBM interactive product. Provides facilities to edit datasets, submit JCL, and set up datasets amongst other things. Often the term is used to describe/include ISPF, which runs under TSO.
 ISPF = An interactive system that runs under TSO. Uses screens to navigate through options. Similar Products are CA's ROSCOE and Skybird Systems' RPF.
 DASD = Direct Access Storage Device, also known as a disk (or disc) although it can refer to any storage device which allows Direct Access to the data stored on it (ie you don't have to read sequentially through all the preceeding files to get to the one you want)
VSAM = A special type of file. There are a number of different types of VSAM files which can be accessed in a number of different ways, including sequentially or using an index.
 Initiator = A system routine which selects which job is to run next, and controls it's execution and termination. There may be a number of initiators in a system, each of which is set up to run different classes of job.
JES = Job Entry Subsystem. JES is a system that is designed to handle execution of all the jobs on the mainframe. It comes in two flavours - JES2 and JES3. JES2 is probably the most commonly used version of JES.


The Job Card


Every job you code will have a Job Card. This is the first thing you must code for every job.
 Each job card will have a jobname to identify the individual job. The jobname does not have to be unique, you can have several jobs with the same name. (The system will automatically allocate a job number when the JCL runs, this helps identify individual jobs when they have the same name).
 

Example:
//HERC04J1 JOB (PJ0001),CLASS=A,MSGCLASS=C,
//           MSGLEVEL=(1,1),NOTIFY=HERC04

The jobname is specified first, in this case HERC04J1. Then the word JOB is specified to indicate that this is a job. You MUST specify the word JOB on the first card.
The (PJ0001) is accounting information. This can indicate an 'accounting cost centre' where the job is to be charged to. The cost centre information varies from site to site.
 The cost centre can be used if your computer centre charges individual departments for usage of the system. Regardless of whether it is used to charge departments, you usually need to specify a cost centre (This may just be your userid eg (HERC04).
You can also specify additional accounting information, such as room number where output is to be sent to, but this is not often used. If you are only specifying a cost centre then the brackets are not required.
 The job class is specified using 'CLASS=' The job class is used to tell the system how the job is to be run. The job class in some cases can decide the priority of the job and how long it will be allowed to run. Jobs are started using OS initiators. Each initiator will be assigned one or more classes of jobs which it can run. So you might have an initiator that runs all Class A jobs and another initiator that runs class B and C jobs. If an initiator is already running a job, then your job may have to wait until the initiator is free.
You can specify where the job output will be directed by using MSGCLASS. The output class may determine what happens to the output. For example Class C may mean that the job is to be held on the system for 8 days before it is deleted, or it may mean that the output is sent immediately to a specific printer.
The system will issue messages when your job is running. You can use the MSGLEVEL parameter to tell the system the type of messages you want to be kept. MSGLEVEL=(1,1) means that all the messages are kept. MSGLEVEL=(0,0) or MSGLEVEL=0, means that the minimal set of messages are kept.
If you want to be told when the job has finished you can use the NOTIFY parameter. The NOTIFY parameter will specify a userid. If you are logged on to TSO then you will be notified when the job ends if you are logged in using that userid or when you log in with that userid.



Job Steps

After the Job Card has been coded you can begin to specify the steps for a job. There can be one or more steps, each of which specifies a program that is to be run. After you tell the system which program to run, you then specify the datasets to use for that program, and where to direct output from that program.
 Each step will have a step name coded in columns 3 onward. A stepname can be 1 to 8 characters long.

Example:


//STEP010 EXEC PGM=DATEST


STEP010 is the step name. The stepname can be anything you want.
EXEC PGM=DATEST tells the system that you want to EXECute a ProGraM called DATEST



Defining datasets to be used in a job step

You tell the system about the datasets you want to use, by specifying a 'DD statement'. DD means Data Definition.
The DD Statement has a DDNAME, this will correspond to the name defined in your program using the SELECT statement (in COBOL).

SELECT REPORT-FILE ASSIGN REPRT1.
 

REPORT-FILE refers to the FD description in your program, the REPRT1 corresponds to the DDName in the JCL.

//REPRT1 DD DSN=HERC04.REPORT.DS1,DISP=SHR 

DSN specifies the dataset name. This is followed by a DISPosition parameter. This tells the system how to access the dataset and whether the dataset already exists.
DISP=OLD, means that the dataset exists and this job should have exclusive use of the dataset.
DISP=SHR, means that the dataset exists and other users and jobs can access the dataset while this job is using it.
DISP=MOD means that the contents of the dataset should be kept and any new records will be appended at the end of the dataset. The dataset may or may not exist already. If it does not exist then one will be created.
DISP=NEW means that the dataset does not exist and will be created when the job is run.



Defining a new dataset.

If you want to create a new dataset during a job run, you use the DD statement. The DD statement will specify, amongst other things,the dataset attributes, where to store the dataset and how much space to be used for the dataset.

//NEWDS DD DSN=HERC04.OUTPUT.CLIENT,
//         DISP=(NEW,CATLG,DELETE),
//         UNIT=3390,SPACE=(TRK,(1,1)),
//         DCB=(RECFM=FB,LRECL=80,BLKSIZE=8000)
 

The DISP parameter specifies that this is a NEW dataset. The second subparameter, CATLG, specifies what will happen to the dataset when the job step ends normally, in this case CATLG means that the dataset is kept and cataloged. You can also specify DELETE or KEEP. DELETE means that the dataset will be deleted and uncatalogued. KEEP specifies that the dataset will be kept, but not catalogued. KEEP is generaly used more with tapes and cartridges than DASD datasets.
The last sub-parameter of the DISP statement, in this case DELETE, specifies what happens to the dataset when the job step terminates abnormally. Again you can specify CATLG, DELETE or KEEP.
 

The UNIT parameter specifies the type of media the dataset will be stored on. '3390' means that the dataset will be stored on a 3390 type disk pack. You can also specify a generic group name, which specifies a group of devices where the dataset can be stored. for example UNIT=SYSDA. This would store the dataset on one of the packs defined within the group SYSDA.
 

The SPACE parameter defines the amount of storage that will be allocated to a dataset. TRK specifies the units, it can be CYL for cylinders, BLK for blocks and TRK for tracks.
The (1,1) specifies the number of tracks/cylinders/blocks. The first number is the number of tracks initially allocated. The second number specifies the number of extents.
 

The DCB parameter tells the job the attributes of the dataset. RECFM defines the format of the dataset, FB means the dataset will have fixed length records and will be blocked, VB would mean the dataset is variable length and blocked.
 

The LRECL subparameter specifies the length of the records that will be in the dataset.
 

The BLKSIZE subparameter specifies the size of a block. It should be a multiple of the record length defined in LRECL. A blocksize of 8000 would hold 100 80 byte records.
For variable length records the blocksize should be a multiple of the record length plus four. The extra four is for the Record Descriptor Word (RDW), this will contain the length of the record. The RDW is not normally visible to your program, but is used by the system, so you must remember to allow for it in the JCL.


Note, you don't have to code the subparameters in any specific order, so your DCB= can come before the SPACE and/or UNIT sub parameters if you wish.



Dataset Concatenation

You can specify multiple datasets on a DD statement. The datasets will be read as if they were all one big dataset.

//DD01 DD DSN=PROD.CLIENTS.LIST1,DISP=SHR
//     DD DSN=PROD.CLIENTS.LIST2,DISP=SHR
//     DD DSN=PROD.CLIENTS.LIST3,DISP=SHR


In this example (assuming the program is reading sequentially through all records), the dataset PROD.CLIENTS.LIST1 will be read until there are no more records, then PROD.CLIENTS.LIST2 will be read until there are no more records then PROD.CLIENTS.LIST3 is read until there are no more records and an end-of-file condition will be returned to the program.



Directing Output

You can specify where your output will be sent using a SYSOUT statement on the DD statement. The statement will contain an output class. The output class determines what will happen to the output. For example, class A might send the output directly to a printer, class C might save the output on the system for seven days, before it is deleted. The output classes will be site specific, check the standards to find out what output classes you should use.

Examples:


//REPRT1 DD SYSOUT=A
//REPRT2 DD SYSOUT=*

If you specify SYSOUT=* then the job class will be the same as that specified in the MSGCLASS in the job card.
If you are using a DISPLAY in your program, then you can use the DDname SYSOUT to direct what happens to the information that is displayed.

 Example:

//SYSOUT DD SYSOUT=X



Passing Parameters to your Program

You can pass parameters to your program by using the SYSIN DDname
Example:
 

COBOL Program:


ACCEPT PARM-LIST FROM SYSIN 
JCL:


//SYSIN DD *
PGM1 20010201 20010301D
//*


The DD * tells the system that what follows is 'instream data'. It is included in the JCL rather than being read from a dataset. The instream data is terminated by either a '/*' (see below) or a new JCL statement being encountered.
In this example 'PGM1 20010201 20010301D' will be passed to the program and stored in the variable PARM-LIST.
Sometimes you will see a '/*' (slash followed by an asterisk) after the parameters (in columns 1 and 2), this tells the system that the instream data is at an end. In most cases you do not need to specify '/*', but it can sometimes be helpful to do so, for example if the SYSIN data is the last thing in the JCL. Eg.


//SYSIN DD *
PGM1 20010201 20010301D
/*


Alternatively you can pass the parameters using the PARM parameter on the EXEC PGM statement.
EG:


//STEP010 EXEC PGM=REPP01,PARM='PGM1 20010201 20010301D' 

This example will achieve exactly the same effect as the SYSIN statement in the previous example. Note that because there are spaces in the parameter you need to enclose the parameter in quotes. The quotes are not considered to be part of the parameter, so they are not passed to the program.
 


JCL PROCs
If you use a piece of JCL often, for example if it is used in several jobs or used in several job steps, then you can define a piece of JCL in a procedure (PROC).
The PROC can be stored in a separate library (PDS) or within the job (an 'In-stream Proc'). JCL in the proc will then be copied into the job and executed as if it was part of the original JCL.
If you store the proc in a library, then the library must be known to the system. Most systems will search a list of libraries to find a proc, if you put your proc into a dataset that is not in this list then the proc will not be found. (Note that you can specify the PROC libraries to be searched, using the JCLLIB statement, although this was not available in earlier versions of MVS).
A JCL Proc is identified by the 'PROC' statement as the first statement.
 Example:


//PH001A PROC 

The 'PH001A' is the name of the PROC, this should be the same as the partitioned dataset member name.
You execute the PROC using an EXEC statement:
 

//STEP050 EXEC PH001A 
If the proc is to be included in the JCL as an in stream proc the proc will be defined first in the JCL before the EXEC procname statement. Instream PROCs must be terminated with a PEND statement. The PEND is not required if the PROC is stored in a PDS.

Example:

//HERC04 JOB(IF0001),CLASS=A,MSGCLASS=X,
//         MSGLEVEL=(1,1)
//*
//PPH001  PROC
//STEPP01 EXEC PGM=IEFBR14
//DD01    DD DSN=HERC04.DATSET.DD01,DISP=SHR
//*
// PEND
//*
//STEP010 EXEC PPH001
//*


You can also specify substitution parameters to customise the JCL to a particular set of circumstances. Substitution parameters are variable names that take on a specified value when you execute the proc. For example if you want to run the same proc in different environments, you may have different dataset names, so instead of having a different proc for each environment you can use the same one but with different values for each environment.
If you are running the same proc for say production systems and development systems, but in production datasets begin with, say PROD, and development datasets begin with DEV, then substitution parameters are ideal. Alternatively you may want to specify a different output class each time you run a proc, again substitution parameters are useful.
You specify that you want to use a substituted value by prefixing the variable name with an '&' symbol.


//SYSOUT DD SYSOUT=&OCLASS 

When you submit the JCL to be run, the &OCLASS will be replaced by whatever value is assigned to it. You can assign a value in a couple of different ways.

1) You can specify the value on the PROC statement.
 

//PROC1 PROC OCLASS=A,JCLASS=B 
In this case each time the proc is run &OCLASS will be substituted by the letter A, and &JCLASS will be substituted by the letter B.

You can override these values on the EXEC procname statement.

 //HERC04 JOB XYX000,CLASS=A,MSGLEVEL=(1,1),
//         NOTIFY=HERC04,MSGCLASS=Q
//*
//STEP010 EXEC PROC1,OCLASS=X,JCLASS=Y
//*
//STEP020 EXEC PROC1,OCLASS=R,JCLASS=S
 

In this example PROC will be executed twice. The first time the proc is executed OCLASS will be substituted by X, JCLASS will be substituted by Y. On the second execution of the proc OCLASS will be substituted by R, and JCLASS will be substituted by S.
 

2) You can use the JCL SET statement.
 

//OCLASS SET OCLASS=X
//JCLASS SET JCLASS=Y
 

The SET statement can appear anywhere in the JCL (as long as it is after the job card), including inside the proc.

//HERC04 JOB XYX000,CLASS=A,MSGLEVEL=(1,1),
//   NOTIFY=HERC04,MSGCLASS=Q
//*
//OCLASS  SET OCLASS=X
//JCLASS  SET JCLASS=Y
//STEP010 EXEC PROC1
//*
//OCLASS  SET OCLASS=R
//JCLASS  SET JCLASS=S
//STEP020 EXEC PROC1


Note that the 'ddname' of the SET statement does not have to be the same as the variable name you are setting, it can be anything you want, but it is neater to have them the same.
If you use a variable name on a dataset name and the variable name is followed by a period (.) then you MUST include an extra period after the variable name. This is so that the system knows where the variable name ends.
For example if your dataset name is PROD.CLIENTS.LIST and you want to have a variable &ENV for the 'PROD' part of the name you would have to specify the name in the JCL as &ENV..CLIENTS.LIST


//HERC04J JOB XYX000,CLASS=A,MSGLEVEL=(1,1),
//    NOTIFY=HERC04,MSGCLASS=Q
//ENV     SET ENV=PROD
//*
//PROC1   PROC
//STEP010 EXEC PGM=REPRTPGM
//*
//DD01    DD DSN=&ENV..CLIENTS.LIST,DISP=SHR
//*
// PEND
//*
//STEP010 EXEC PROC1


When this jcl is executed the dataset name will be interpreted as PROD.CLIENTS.LIST. If you were to forget the extra period then the name would be interpreted as PRODCLIENTS.LIST and you would get a JCL error, because
 1) the dataset does not exist and
 2) the first part of the name is longer than 8 characters.



STEPLIBs and JOBLIBs

Sometimes you have to tell the computer where your program is located. (For example, if you have the program located in your own private library, or if you want to test a new version of your program without disturbing the existing program). You can use STEPLIB and JOBLIB to tell the computer where the program you want to run will be.
STEPLIB and JOBLIB will have a DD statement, containing the names of the Load Libraries that are to be looked at in order to find the program.
As their names imply, STEPLIB applies only to a particular Job Step, while JOBLIB applies to the whole job.
If you specify both, then the STEPLIB will override anything specified in the JOBLIB, but only for that particular step.
A JOBLIB statement will be specified after the Job Card, but before any Job steps. The STEPLIB will be specified after the EXEC PGM statement of the job step.


//HERC04J JOB (HERC04),'HERC04',CLASS=A,MSGCLASS=T
//JOBLIB DD DSN=GEN00.DEV.LOADLIB,DISP=SHR
//*
//STEP010 EXEC PGM=PROGR1
//*
//STEP020 EXEC PGM=PROGR2
//STEPLIB DD DSN=TRT01.DEV.LOADLIB,DISP=SHR
//*
//STEP030 EXEC PGM=PROGR3
//*
//STEP040 EXEC PGM=PROGR4


In this example the programs PROGR1 (in STEP010), PROGR3 (in STEP030) and PROGR4 (in STEP040) will all be run from the library GEN00.DEV.LOADLIB, because it is specified in JOBLIB. PROGR2 (in STEP020) will be run from TRT01.DEV.LOADLIB, because it is specified in the STEPLIB, and the STEPLIB overrides the JOBLIB.



No comments:

Post a Comment

Note: Only a member of this blog may post a comment.