JCL

Job Control Language (JCL) is a scripting language used on a mainframe to instruct the system on how to run a batch job. In AWS Transform for mainframe refactor, it is handled in the mainframe group following the statements listed below.

Properties attached to JCL dependencies (symbolic, JCL.PartitionedDataSet, JCL.ddnameToDataset, JCL.gdgOperation, JCL.db2Plan, FTP.RemoteHost) are described in the Dependency properties page.

JCL Statements

DD DSN

The call on DD +DSN can imply dependencies on "DATASET or Partitioned DataSet" object, "FILE_DEFINITION" object and a control card (.CTL).

//file-definition-name DD (DISP=disposition,)? DSN(AME)?=dataset-or-PDS-name(controlcard-file-or-generation)

Where 

  • file-definition-name: the DD name. When a program executed in the same step declares a file with that name, a "File declaration assignement" dependency is created from the JCL to the file object: a Cobol FD file-definition-name, a PL/I DCL file-definition-name FILE or an Easytrieve FILE file-definition-name (see the PL/I and EZT pages).
  • disposition: the "DISP" status of the dataset (optional)
  • dataset-name: a "DATASET" object or a Partitioned DataSet (PDS) object.
  • controlcard-file-or-generation: either a control card name in the project OR a GDG generation number (optional)

The dependency type is taken from the disposition. DISP=OLD and DISP=SHR create a "Read Dataset" dependency, any other status and a missing DISP create a "Write Dataset" dependency. When the same dataset is read in one step and written in another, both types are reported.

The parentheses content can be:                   
1. Control card file: A control card name. In this case, the dataset-or-PDS-name will create a dependency to a PDS object and the control card dependency will have the property JCL.PartitionedDataSet. This allows reconstruction of the fully qualified DSN to locate the control card in case it was missing.                   
2. GDG generation: A generation number for Generation Data Groups:                   
  - (0) or (+0): refers to the most current generation                   
  - (-1): refers to the previous generation                     
  - (+1): specifies a new generation to be added                   
  - Other numeric values like (-2), (+2), etc.

GDG generation linked to its GDG base

When the GDG base is defined in the project — by a DEFINE GENERATIONDATAGROUP / DEFINE GDG IDCAMS command (see IDCAMS) or by a GDG BASE entry of a LISTCAT file — a generation reference such as DSN=APP.PROD.NEXT(+1) is linked to the GDG base node APP.PROD.NEXT instead of to a dataset named APP.PROD.NEXT(+1). The base can be defined in any file of the project. The dependency also carries:

  • the property JCL.gdgOperation, holding the relative generation without its parentheses (+1, -1, 0)
  • an additional dependency type: GDG increment for (+n), GDG decrement for (-n) or GDG latest for (0) / (+0)

When no GDG base is defined, the dependency is left unchanged: it targets APP.PROD.NEXT(+1) and is reported as "Missing Dataset" if that dataset is not in the codebase.

Example:

//STEP10  EXEC PGM=IDCAMS
//SYSIN    DD *
   DEFINE GENERATIONDATAGROUP (NAME(APP.PROD.NEXT) LIMIT(5))
   DEFINE GENERATIONDATAGROUP (NAME(APP.PROD.PREV) LIMIT(5))
/*
//STEP20  EXEC PGM=IEFBR14
//NEWGEN   DD DISP=(NEW,CATLG),DSN=APP.PROD.NEXT(+1)
//OLDGEN   DD DISP=SHR,DSN=APP.PROD.PREV(-1)
//UNDEF    DD DISP=(NEW,CATLG),DSN=APP.PROD.UNDEFINED(+1)

Creates:

{
    "dependencyType": "Define DATASET; GDG increment; Write Dataset",
    "name": "APP.PROD.NEXT",
    "path": "Global:DATASET:APP.PROD.NEXT",
    "type": "GDG BASE",
    "properties": {
        "JCL.gdgOperation": "+1"
    }
}

and

{
    "dependencyType": "Define DATASET; GDG decrement; Read Dataset",
    "name": "APP.PROD.PREV",
    "path": "Global:DATASET:APP.PROD.PREV",
    "type": "GDG BASE",
    "properties": {
        "JCL.gdgOperation": "-1"
    }
}

and, for the base that is not defined:

{
    "dependencyType": "Write Dataset",
    "name": "APP.PROD.UNDEFINED(+1)",
    "path": null,
    "type": "Missing Dataset"
}

"Define DATASET" appears in the dependency type because the GDG bases are defined in the same JCL. The "Read Dataset" / "Write Dataset" type comes from the DISP of the DD statement.

Names containing %% (system symbols) are dynamic and are not resolved. Names containing & are symbolic parameters and are resolved when possible, see Symbolic values.

When the file-definition-name is equal to STEPLIB, JOBLIB, or JCLLIB, a PDS dependency is created instead of a DataSet dependency. This helps distinguish between DataSets that are files and Partitioned DataSets that are folders.

Examples:

//SYSIN DD DSN=MY.LIB.AWS(MYCTL),DISP=SHR

Creates:

{
    "dependencyType": "Control card",
    "name": "MYCTL",
    "properties": {
        "JCL.PartitionedDataSet": "MY.LIB.AWS"
    },
    "path" : "MY.LIB.AWS/MYCTL",
    "type" : "CTL"
}

and 

{
    "dependencyType": "PDS use",
    "name": "MY.LIB.AWS",
    "path": "Global:PDS:MY.LIB.AWS",
    "type": "PDS"
}

Locating the PDS of a control card

The PDS object of a DSN=pds-name(member) reference is resolved in two ways:

  • a folder named pds-name exists in the project, or
  • the member is found as a control card file anywhere in the project, whatever the name of its folder. The PDS object is then created from the JCL.PartitionedDataSet property carried by the control card dependency, provided pds-name is a valid dataset name (at least two qualifiers of 1 to 8 characters separated by periods).

When neither applies, the PDS dependency is reported as "Missing PDS". A plain DSN=pds-name without a member is only resolved through a folder of that name.

Example, with the control card stored as cards/CARDMBR.ctl:

//SYSTSIN  DD DISP=SHR,DSN=APP.CTRL.CARDLIB(CARDMBR)

Creates:

{
    "dependencyType": "PDS use",
    "name": "APP.CTRL.CARDLIB",
    "path": "Global:PDS:APP.CTRL.CARDLIB",
    "type": "PDS"
}

and

{
    "dependencyType": "Control card",
    "name": "CARDMBR",
    "path": "cards/CARDMBR.ctl",
    "type": "CTL",
    "properties": {
        "JCL.PartitionedDataSet": "APP.CTRL.CARDLIB"
    }
}

For library statements such as STEPLIB, JOBLIB, and JCLLIB, only one PDS dependency is created.

Load libraries

A dataset whose last qualifier is LOADLIB (*.LOADLIB, any case) is a load module library: it has no source in the project and no purpose after migration. When such a dataset is not found in the project it is typed "System" instead of "Missing PDS" or "Missing Dataset". The dependency type is unchanged ("PDS use", "Read Dataset" or "Write Dataset"). The rule is applied after symbolic resolution; a (member) control card referenced in the same DSN is not affected. Other library naming conventions (LINKLIB, LOAD, …) are not recognised.

//STEPLIB  DD DSN=CUSTOMER.APP.LOADLIB,DISP=SHR
//INPUT    DD DSN=CUSTOMER.APP.DATA,DISP=SHR

Creates:

{
    "dependencyType": "PDS use",
    "name": "CUSTOMER.APP.LOADLIB",
    "path": null,
    "type": "System"
}

and

{
    "dependencyType": "Read Dataset",
    "name": "CUSTOMER.APP.DATA",
    "path": null,
    "type": "Missing Dataset"
}

Plain reference to a GDG base

A dataset name used without parentheses refers to the most current generation. When the same name is also used with a generation number elsewhere, the dependency is named dataset-name(0). A base defined in the project resolves to its GDG BASE node and keeps its plain name.

Example

//SORTOUT  DD DISP=(NEW,CATLG),DSN=APP.PROD.PAIR(+1)
//SORTIN   DD DISP=SHR,DSN=APP.PROD.PAIR

Creates:

{
    "dependencyType": "Write Dataset",
    "name": "APP.PROD.PAIR(+1)",
    "path": null,
    "type": "Missing Dataset"
}

And

{
    "dependencyType": "Read Dataset",
    "name": "APP.PROD.PAIR(0)",
    "path": null,
    "type": "Missing Dataset"
}

PROC DD DSN with symbolic PDS

When a PROC's DD statement references a PDS via a symbolic parameter whose value is supplied (or overridden) by the calling JCL — for example DSN=&CARDLIB(MY_CTL) with &CARDLIB defined on the JCL — the control card dependency is attached to the calling JCL rather than the PROC. The JCL.PartitionedDataSet property on the JCL-side edge is resolved against the caller's symbolic context so the fully qualified dataset name is visible, while the PROC loses the edge because its PDS name is unknown at the PROC level.

When the same PROC is invoked from multiple JCLs with different symbolic values, each caller JCL receives its own resolved copy of the dependency. Standalone PROCs (never called from any JCL) keep their control-card edge untouched with the symbolic property left as-is.

Example: a PROC PROC1.proc with //SYSIN DD DSN=&CARDLIB(MY_CTL),DISP=SHR called from JOB1.jcl where &CARDLIB=LIB.DATA produces on JOB1.jcl: 

{
	"dependencyType": "Control card", 
	"name": "MY_CTL",
	"path": "LIB.DATA/MY_CTL",
	"type": "CTL",
	"properties": { "JCL.PartitionedDataSet": "LIB.DATA" }
} 

and no matching edge on PROC1.proc.

SYSIN control card resolving to an EZT program

When a step runs an Easytrieve program through the Easytrieve runtime (EXEC PGM=EZTPA00), the EZT source is supplied as a control card on the SYSIN DD. The SYSIN member resolves to the EZT source file as a "Control card" dependency of type EZT (in addition to the CTL type produced for a control-card file).

Example:

//STEP01  EXEC PGM=EZTPA00
//SYSIN    DD DISP=SHR,
//         DSN=AWS.M2.CARDDEMO.EZTLIB(CUSTREP1)

Output:

{
 "dependencyType": "Control card",
 "name": "CUSTREP1.EZT",
 "path": "dependencies/CUSTREP1.EZT",
 "properties": {
     "JCL.PartitionedDataSet": "AWS.M2.CARDDEMO.EZTLIB"
 },
 "type": "EZT"
}

DLBL

The call to DLBL implies a dependency on a Mainframe file.

  • DLBL file_def 'mainframe_file'

Where file_def is the name of the file definition and mainframe_file the name of a mainframe file in the project.

MQN

An MQN (Message Queue Name) represents a message queue configuration.

MQN NAME=<mqn-name>

The MQN statement defines a message queue object. It creates a dependency link of type "Define Queue" between the MQN and the referencing object.

EXEC

EXEC statements like NAME1.NAME2.EXEC imply a dependency on a JCL, PROC, COB, EZT, REXX, PL1, CLIST or RPG file.

  • NAME1.NAME2.EXEC(MY_PROG) implies a dependency on the program MY_PROG where NAME1 and NAME2 can be any valid names
  • NAME1.EXEC(MY_PROG) implies a dependency on the program MY_PROG where NAME1 can be any valid name

EXEC PGM

The call to EXEC PGM implies a dependency on a COB, EZT, REXX, PL1 or RPG file.

  • EXEC PGM=program_file ... PROGRAM=program
  • EXEC PGM=program_file ... PROG=program
  • EXEC PGM=program_file ... PGMNAME=program
  • EXEC PGM=program_file ... PGMNAME='program'
  • EXEC PGM=system_utility PARM=(program_type,program_name,psb_name, ...) ... PROGRAM=program
  • EXEC PGM=system_utility PARM=('program_type',program_name,psb_name, ...) ... PROGRAM=program
  • EXEC PGM=system_utility PARM='program_type,program_name,psb_name, ...' ... PROGRAM=program
  • EXEC PGM=system_utility PARM=(program_type,program_name,psb_name,'PROG(nested_program)', ...) ... PROGRAM=program

Where program_file can be the raw name of a file or a variable (&program_file) containing a filename. PROGRAM, PROG and PGMNAME are parameters passed to program_file and program (JCL, PROC, COB, EZT, REXX, PL1, RPG or CCDEF) the name of the program to be executed. PARM=( ... ) or PARM=' ... ' is an optional parameter.                   
When system_utility is configured with some system utility program (DFSRRC00, DLIBATCH, DBBBATCH, IMSBATCH, IMSFP and DLIBMP) and the program_type is DLI, BMP, DBB or IFP, the system utility program uses the PARM parameter to execute a program (COBOL, JCL, PROC, REXX, PL1, RPG, ASM, LNK, EZT, CTL or CCDEF) mentioned in program_name and the PSB file mentioned in psb_name.                   
Inside the PARM parameter, we can find a PROG call where nested_program will be the name of an existing file in the project. This nested parameter will create another link to nested_program.                   
We can also call an in-stream procedure thanks to the EXEC PGM statement. In that case, it will create no dependency.

DD to dataset mapping (JCL.ddnameToDataset)

The "Exec program" dependency created by EXEC PGM=program carries a JCL.ddnameToDataset property listing the datasets allocated to the program by the DD statements of its step. Each entry is STEP.DDNAME=DSN (or DDNAME=DSN when the EXEC statement has no step name); entries are separated by ;, sorted alphabetically and de-duplicated. A concatenated DD (//         DD DSN=… continuation cards) produces one entry per dataset, all with the same STEP.DDNAME key. When the same program is executed by several steps or several JCLs, the mappings are merged on the single "Exec program" dependency.

The property is carried by "Exec program" dependencies only, including those typed "System" (SORT, IKJEFT01, …). It is not carried by EXEC PROC= dependencies, and the DD overrides that follow an EXEC PROC are not mapped.

Not listed: DD *, DD DATA, DD DUMMY, SYSOUT= and NULLFILE allocations, temporary datasets (&&TEMP), names containing %%, and names whose symbolic parameters are still unresolved.

Example:

//STEP1    EXEC PGM=CBTRN02C
//ACCTFL   DD DSN=AWS.M2.CARDDEMO.ACCTDATA.PS,DISP=SHR
//INPUT    DD DSN=AWS.M2.CARDDEMO.FIRST.PS,DISP=SHR
//         DD DSN=AWS.M2.CARDDEMO.SECOND.PS,DISP=SHR
//SYSOUT   DD SYSOUT=*

Creates:

{
    "dependencyType": "Exec program",
    "name": "CBTRN02C",
    "path": null,
    "type": "Missing Program",
    "properties": {
        "JCL.ddnameToDataset": "STEP1.ACCTFL=AWS.M2.CARDDEMO.ACCTDATA.PS;STEP1.INPUT=AWS.M2.CARDDEMO.FIRST.PS;STEP1.INPUT=AWS.M2.CARDDEMO.SECOND.PS"
    }
}

See the Dependency properties page for the full list of properties.

EXEC PROC

The call to EXEC PROC implies a dependency on a JCL, PROC, COB, EZT, REXX, PL1, CLIST, RPG or CCDEF file.

  • EXEC PROC=procedure_file ... PROGRAM=program
  • EXEC PROC=procedure_file ... PROG=program
  • EXEC PROC=procedure_file ... PGMNAME=program
  • EXEC proc=procedure_file ... PGMNAME='program'
  • EXEC procedure_file ... PROGRAM=program
  • EXEC procedure_file ... PROG=program
  • EXEC procedure_file ... PGMNAME=program
  • EXEC procedure_file ... PGMNAME='program'
  • EXEC PROC=system_utility ... NAME=program,PSB=psb_name
  • EXEC system_utility ... NAME=program,PSB=psb_name

Where procedure_file can be the raw name of a file or a variable (&procedure_file) containing a filename. PROGRAM, PROG and PGMNAME are parameters passed to procedure_file and program the name of the program to be executed.                   
When system_utility is configured with some system utility program (DFSRRC00, DLIBATCH, DBBBATCH, IMSBATCH, IMSFP and DLIBMP) then it executes a program (COBOL, JCL, PROC, REXX, PL1, RPG, ASM, LNK, EZT, CLIST, CTL or CCDEF) mentioned in program_name and the PSB file mentioned in psb_name.                   
We can also call an in-stream procedure thanks to the EXEC PROC statement. In that case, it will create no dependency.

IKJEFT01 with PGM01

When a step executes the IKJEFT01 procedure and passes the program to run through a PGM01= parameter, a second "Exec program" dependency is created on that program, alongside the dependency on IKJEFT01 itself (typed "System" when the utility is in the system utilities catalog).

//STEP01   EXEC IKJEFT01,
//         DB2ID=VAL1,
//         PGM01=VAL2,
//         PLAN01=VAL3

Creates:

{
    "dependencyType": "Exec program",
    "name": "IKJEFT01",
    "path": null,
    "type": "System"
}

and

{
    "dependencyType": "Exec program",
    "name": "VAL2",
    "path": null,
    "type": "Missing Program"
}

Only the PGM01 parameter is recognised; the value can be a symbolic parameter, resolved as described in Symbolic values. A program named in the SYSTSIN in-stream data (RUN PROGRAM(…)) is handled by the RUN PROGRAM statement.

ISPSTART CMD

The call to ISPSTART CMD can be used to reference a program (COBOL, JCL, PROC, REXX, PL1, RPG, ASM, LNK, EZT, CLIST or CTL) 

  • ISPSTART CMD(MY_PROG) implies a dependency on a program called MY_PROG

RUN PROG

The call to RUN PROG implies a dependency on a JCL, PROC, COB, EZT, REXX, PL1 or RPG file.

  • RUN PROG(program_file)

Where program_file can be the raw name of a file or a variable (&program_file) containing this name.

RUN PROGRAM

The call to RUN PROGRAM implies a dependency on a JCL, PROC, COB, EZT, REXX, PL1 or RPG file.

  • RUN PROGRAM(program_file)

Where program_file can be the raw name of a file or a variable (&program_file) containing this name.

SQL STATEMENT

In a JCL program, SQL statements are executed in the in-stream data section. In-stream data never begins with //. The end of the in-stream data is identified by a line beginning with // or /* or //*, or sometimes by the end of the file.

  • //SYSIN DD *                   
    SELECT * FROM TABLE_NAME;
  • //SYSIN DD DATA                   
    UPDATE TABLE_NAME SET COLUMN1 = VALUE1 WHERE ...;

Note: not all in-stream data are SQL commands. It may be a RUN PROGRAM statement or others.

FTP

When a step executes the FTP utility, // EXEC PGM=FTP, the in-stream data of the step (//SYSIN DD * or //INPUT DD *) is analysed for file transfers:

  • PUT 'DATASET.NAME' remote-file and MPUT 'DATASET.NAME' ... imply a dependency of type "FTP put" on a dataset named DATASET.NAME
  • GET 'DATASET.NAME' local-file and MGET 'DATASET.NAME' ... imply a dependency of type "FTP get" on a dataset named DATASET.NAME

Surrounding quotes are removed from the dataset name. The remote host is taken from PARM='host ...' on the EXEC statement when present, otherwise from the first in-stream line that is not an FTP subcommand (ASCII, BINARY, EBCDIC, CD, LCD, PWD, DIR, QUIT, ...). It is stored in the FTP.RemoteHost property of the dependency. The in-stream data ends at /* or at the next // statement.

Example:

//STEP01  EXEC PGM=FTP,PARM='192.168.10.5 (EXIT'
//SYSIN   DD *
 USERID PASSWORD
 BINARY
 PUT 'PROD.OUT.DAILY' daily.dat
 GET 'PROD.IN.RESPONSE' response.dat
 QUIT
/*

Creates:

{
    "dependencyType": "FTP put",
    "name": "PROD.OUT.DAILY",
    "path": null,
    "type": "FTP Dataset",
    "properties": {
        "FTP.RemoteHost": "192.168.10.5"
    }
}

and

{
    "dependencyType": "FTP get",
    "name": "PROD.IN.RESPONSE",
    "path": null,
    "type": "FTP Dataset",
    "properties": {
        "FTP.RemoteHost": "192.168.10.5"
    }
}

When at least one transfer is found, the generic "Exec program" dependency on the FTP system utility is not created for that step. A dataset that is not in the codebase is reported as "Missing Dataset".

CMSYNIN

A Natural batch step names the program it runs in its //CMSYNIN DD * command stream, not on the EXEC statement, which carries the Natural nucleus. The program is the first command after LOGON, before FIN.

  • //CMSYNIN DD *                  
    LOGON library                  
    program                  
    FIN

Where program is the name of a Natural program in the project. The nucleus and the program are sibling "Exec program" dependencies, as for IKJEFT01. Detection is on the CMSYNIN DDNAME rather than on the nucleus name, which is site-specific, so a renamed nucleus still creates the dependency. The nucleus is typed "System" when it matches the system utilities catalog, where NATBAT is registered as a prefix.

A Natural program reaches its work files through the CMWKFnn DDs of its own step, so the JCL.ddnameToDataset property is carried by the program's dependency with the mapping of that step only, while the nucleus keeps the mapping merged across steps.

Example:

//STEP1    EXEC PGM=NATBAT
//STEPLIB  DD DSN=NATURAL.LOAD,DISP=SHR
//CMSYNIN  DD *
LOGON MYLIB
NATPGM01
FIN
/*
//CMWKF01  DD DSN=SAMPLE.EXTRACT.CSV,DISP=SHR

Creates:

{
    "dependencyType": "Exec program",
    "name": "NATPGM01",
    "path": null,
    "type": "Missing Program",
    "properties": {
        "JCL.ddnameToDataset": "STEP1.CMWKF01=SAMPLE.EXTRACT.CSV;STEP1.STEPLIB=NATURAL.LOAD"
    }
}

INCLUDE MEMBER

The INCLUDE MEMBER statement implies a dependency on a Mainframe file. Dependencies with variables starting with "$" are ignored.

  • INCLUDE MEMBER=mainframe_file

Where mainframe_file is the name of a Mainframe file in the project.

ADDRQ

The call to ADDRQ statement implies a dependency on a JCL file, like the following example:

  • ADDRQ,JOB=file_name_1,DEPJOB= file_name_2

Where file_name_1 and file_name_2 can be the names of JCL files.

DEMAND

The call to DEMAND statement implies a dependency on a JCL file, like the following example:

  • DEMAND,JOB=file_name_1,DEPJOB= file_name_2

Where file_name_1 and file_name_2 can be the names of JCL files.

DEMANDH

The call to DEMANDH statement implies a dependency on a JCL file, like the following example:

  • DEMANDH,JOB=file_name_1,DEPJOB= file_name_2

Where file_name_1 and file_name_2 can be the names of JCL files.

MODS

A sort step (SYNCSORT / DFSORT) can name user exit routines on a MODS control statement in its control-card stream (//SYSIN DD *, //SORTCNTL DD *, or a cataloged .CTL member) instead of on the EXEC statement. Each exit is a load module the sort loads and calls, so MODS implies a dependency on a program (COB, PL1, RPG, ASM, EZT, LNK, CTL or CCDEF).

  • MODS exit-point=(module_name,size[,ddname][,linkage])[,exit-point=(module_name, ...)]

Where

  • exit-point is a sort exit identifier: one of E11, E15–E19, E21, E25, E27, E31, E32, E35, E37–E39, E61. E15 is the input-record exit and E35 the output-record exit; these are the most common.
  • module_name is the name of the exit load module in the project — a valid load module name (1 to 8 characters, starting with a letter or a national character @ # $).
  • ddname (optional) is the DD name of the library that holds the exit module (for example STEPLIB), and linkage (optional) is the exit's linkage indicator (for example N). Neither affects the dependency.

Several exits may be named on one card, and a MODS statement may continue across cards; every exit named creates its own dependency. An exit whose module is not in the codebase is reported as "Missing Program". Exit specifications that appear on a // JCL card (for example inside PARM=) are not MODS sort exits and create no dependency.

MODS in a cataloged control card (.CTL) member is analyzed the same way, with the exits attributed to the control card.

Example:

//SORTSTEP EXEC PGM=SORT
//SYSIN    DD *
  SORT FIELDS=(0005,0109,CH,A)
  MODS E15=(SRTEXT15,4096,STEPLIB,N),E35=(SRTEXT35,4096)
/*

Creates:

{
    "dependencyType": "Sort exit routine",
    "name": "SRTEXT15",
    "type": "Missing Program"
}

and

{
    "dependencyType": "Sort exit routine",
    "name": "SRTEXT35",
    "type": "Missing Program"
}

EXEC PGM=DFSRRC00 — DB2 plan (DDITV02)

A step that runs the IMS region controller (EXEC PGM=DFSRRC00, directly or through one of the IMS procedures DLIBATCH, DBBBATCH, IMSBATCH, IMSFP or DLIBMP) and uses DB2 declares a DDITV02 DD pointing at a control card (the ESAF / DB2 connection card). That card names the DB2 plan the step runs — a real dependency even when the program has no EXEC SQL. The DDITV02 control-card member is linked as a "Control card", and its record is parsed to emit a "DB2 plan" dependency of type System[DB2]; the step's program(s) are tagged with the JCL.db2Plan property.

A DDITV02 record is nine comma-delimited positional fields:

ssn,lit,esmt,rtt,reo,crc,connection-name,plan-name,program-name

The extracted plan is field 8 (plan-name), or field 9 (program-name) when field 8 is blank. The resource translation table named in field 4 (rtt) is not resolved.

A DB2 plan is attached to a step only when all of the following hold:

  • DDITV02 fingerprint: the record has exactly 9 comma fields (so the 6-field DFSSSMxx / SSM= connection-only form is skipped), the ESMT (field 3) is a DSNMIN* module, the region-error-option (field 5) is blank or R / Q / A, and the CRC (field 6) is at most one character. This rejects arbitrary 9-field CSV records.
  • IMS region context: the step runs the IMS region controller (DFSRRC00, directly or through DLIBATCH, DBBBATCH, IMSBATCH, IMSFP or DLIBMP). The region controller itself is not tagged.
  • DDITV02 DD reference: the card must be referenced by a DDITV02 DD in the same JCL/PROC file. A file that references the same member through a different DD name (for example SYSIN) does not get a plan node.

Example:

//DLIBSTEP EXEC PGM=DFSRRC00,PARM=(DLI,APPLPGM1,APPLPGM1)
//STEPLIB  DD DSN=IMS.LOADLIB,DISP=SHR
//DDITV02  DD DSN=SAMPLE.DB2.CNTLLIB(DB2CRD01),DISP=SHR

where DB2CRD01.ctl contains:

DSNP,SYS1,DSNMIN10,,R,-,DB2CONN,MYPLAN01,APPLPGM1

Creates a DB2 plan node on the step:

{
    "dependencyType": "DB2 plan",
    "name": "MYPLAN01",
    "type": "System[DB2]"
}

and tags the step's program:

{
    "dependencyType": "Exec program",
    "name": "APPLPGM1",
    "type": "Missing [PSB, Program]",
    "properties": {
        "JCL.db2Plan": "MYPLAN01"
    }
}

IDCAMS

The access method services commands of an IDCAMS step (// EXEC PGM=IDCAMS) are analysed in the in-stream data of the step (//SYSIN DD *) and in cataloged control card (.CTL) members. A command may continue across lines with a trailing -.

DEFINE CLUSTER / DEFINE ALTERNATEINDEX

DEFINE CLUSTER (or DEFINE CL) and DEFINE ALTERNATEINDEX (or DEFINE AIX) create a DATASET object with a VSAM type and a "Define DATASET" dependency, as described for control cards on the CTL page. The VSAM type is given by the organisation keyword: INDEXED / IXD (VSAM KSDS), NONINDEXED / NIXD (VSAM ESDS), NUMBERED / NUMD (VSAM RRDS) or LINEAR / LIN (VSAM LDS). Without such a keyword, a cluster defaults to VSAM KSDS DATASET and an alternate index to VSAM AIX DATASET. For an alternate index, the DATA(...) and INDEX(...) components are optional.

Example:

//STEP20  EXEC PGM=IDCAMS
//SYSIN    DD *
   DEFINE ALTERNATEINDEX (NAME(APP.DATA.MASTER.AIX)  -
   RELATE(APP.DATA.MASTER.KSDS)                      -
   KEYS(8 50)                                        -
   NONUNIQUEKEY                                      -
   UPGRADE                                           -
   RECORDSIZE(200,200)                               -
   CYLINDERS(5,1))                                   -
   DATA (NAME(APP.DATA.MASTER.AIX.DATA))             -
   INDEX (NAME(APP.DATA.MASTER.AIX.INDEX))
/*

Creates the object:

{
    "name": "APP.DATA.MASTER.AIX",
    "path": "Global:DATASET:APP.DATA.MASTER.AIX",
    "type": "VSAM AIX DATASET"
}

DEFINE GENERATIONDATAGROUP

DEFINE GENERATIONDATAGROUP (NAME(gdg-base) ...) (or DEFINE GDG) creates a DATASET object of type GDG BASE and a "Define DATASET" dependency. Generation references to this base, such as DSN=gdg-base(+1), are linked to it (see DD DSN).

Example:

//STEP10  EXEC PGM=IDCAMS
//SYSIN    DD *
   DEFINE GENERATIONDATAGROUP (NAME(APP.PROD.BACKUP.GDG)  -
   LIMIT(10)                                              -
   SCRATCH                                                -
   EMPTY)
/*

Creates:

{
    "dependencyType": "Define DATASET",
    "name": "APP.PROD.BACKUP.GDG",
    "path": "Global:DATASET:APP.PROD.BACKUP.GDG",
    "type": "GDG BASE"
}

BLDINDEX / REPRO

In a BLDINDEX or REPRO command, INDATASET(dataset-name) implies a dependency of type "Read Dataset" and OUTDATASET(dataset-name) a dependency of type "Write Dataset" on a DATASET object. Only the full keywords are recognised: the abbreviations IDS / ODS and the DD name forms INFILE / OUTFILE create no dependency. A dataset that is not in the codebase is reported as "Missing Dataset".

Example:

//STEP30  EXEC PGM=IDCAMS
//SYSIN    DD *
   BLDINDEX                              -
   INDATASET(APP.DATA.MASTER.KSDS)        -
   OUTDATASET(APP.DATA.MASTER.AIX)
/*

Creates a "Read Dataset" dependency on APP.DATA.MASTER.KSDS and a "Write Dataset" dependency on APP.DATA.MASTER.AIX. When both datasets are defined in the same JCL, as in the example above, the types are merged with the definition:

{
    "dependencyType": "Define DATASET; Write Dataset",
    "name": "APP.DATA.MASTER.AIX",
    "path": "Global:DATASET:APP.DATA.MASTER.AIX",
    "type": "VSAM AIX DATASET"
}

and

{
    "dependencyType": "Define DATASET; Read Dataset",
    "name": "APP.DATA.MASTER.KSDS",
    "path": "Global:DATASET:APP.DATA.MASTER.KSDS",
    "type": "VSAM KSDS DATASET"
}

Symbolic values

When possible, the dependency analysis will replace the usage of a symbolic parameter by its value. This applies to all dependency targets and property values — not just dataset names.

Defining symbolic parameters

Symbolic parameters can be defined in three ways:

  • SET statements: // SET BNK=G
  • PROC parameter defaults: //MYPROC PROC BASEOS=APP2.BASE.
  • EXEC statement overrides: // EXEC MYPROC,SYSTEM=SUB1

A PROC may use a symbolic parameter without declaring a default for it (//PROC1 PROC DCLAS=DSIZE500 then DSN=&VAR1.XX.FILEDATA). The value is then taken from the calling JCL, through its SET statements or its EXEC overrides, with the priority described in Resolution process below.

Variable syntax

  • Variables are prefixed with & (e.g., &BNK)
  • A trailing period (.) terminates the variable name and is consumed during resolution: &BNK.TEXT with BNK=G resolves to GTEXT, not G.TEXT
  • Multiple variables can appear in a single value: &VAR1.TEXT&VAR2.

Resolution process

Symbolic resolution happens in two phases:

Phase 1 — Scanning (per-file): Each JCL and PROC file is scanned individually. The analyzer collects symbolic parameter definitions (SET, PROC defaults, EXEC overrides). Dependencies whose target or property values contain & are stored as unresolved at this stage.

Phase 2 — Cross-file resolution (global): After all JCL and PROC files have been scanned, a global post-processor resolves symbolic parameters across file boundaries:

  1. For each JCL file, it walks the dependencies and follows EXEC PROC references into the corresponding PROC files.
  2. It builds a symbolic context from the calling JCL (SET values + EXEC overrides) combined with the PROC's own defaults.
  3. It substitutes & variables in the PROC's dependency targets and property values using this context.
  4. If the PROC calls nested PROCs, the process recurses with the accumulated context.
  5. Chained symbolics (a variable whose value contains another & reference) are resolved iteratively.

Resolution priority (highest to lowest):

  1. EXEC statement overrides from the calling JCL
  2. SET statements in the calling JCL
  3. PROC parameter defaults

Re-parenting to the calling JCL

Once symbolic resolution succeeds, the resolved dependency is moved from the PROC to the calling JCL file. In the dependency graph JSON, the dependency appears under the JCL — not under the PROC.

  • The dependency target name contains the resolved value
  • All property values are resolved
  • Exception: the symbolic property preserves the original unresolved expression. This is the only property that retains the pre-resolution form. When several references written with different symbolic expressions resolve to the same target (for instance &FIXLIB(CARD2) and &JOBLIB(CARD2) with SET FIXLIB=LIB.DATA.TEST,JOBLIB=LIB.DATA.TEST), they are merged into one dependency whose symbolic property lists every origin, separated by ; and sorted:

    {
        "dependencyType": "PDS use; Resolved Symbol",
        "name": "LIB.DATA.TEST",
        "path": "Global:PDS:LIB.DATA.TEST",
        "type": "PDS",
        "properties": {
            "symbolic": "&FIXLIB;&JOBLIB"
        }
    }
  • Exception: a plain GDG reference receives its (0) suffix after resolution, so the target name is the resolved value followed by (0) while the symbolic property keeps the original expression.

When the same PROC is called from multiple JCLs with different overrides, each JCL gets its own resolved copy of the dependency. Standalone PROCs (never called from any JCL) keep their edges untouched with the symbolic property left as-is.

Examples

Multiple symbolics in a dataset name:

// SET BNK=G
// EXEC MYPROC,BASEOS=APP2.BASE.

In the PROC:

//ISPSLIB  DD DSN=&BASEOS.DB2DATA&BNK.,DISP=SHR

Resolution: &BASEOS → APP2.BASE. (trailing period consumed), &BNK → G (trailing period consumed). Resolved name: APP2.BASE.DB2DATAG.

Creates on the calling JCL:

{
    "dependencyType": "Read Dataset; Resolved Symbol",
    "name": "APP2.BASE.DB2DATAG",
    "properties": {
        "symbolic": "&BASEOS.DB2DATA&BNK"
    }
}

Symbolic in member name:

//DB2SORTI DD DSN=PGDF.BASE.DATA(DB2SRT&SORT),DISP=SHR

Given SORT=64, the PDS name PGDF.BASE.DATA is literal and the member DB2SRT&SORT resolves to DB2SRT64.

Creates:

{
    "dependencyType": "Control card; Resolved Symbol",
    "name": "DB2SRT64",
    "properties": {
        "symbolic": "DB2SRT&SORT",
        "JCL.PartitionedDataSet": "PGDF.BASE.DATA"
    },
    "path": "PGDF.BASE.DATA/DB2SRT64",
    "type": "CTL"
}

Symbolic in PDS name with literal member:

// SET BNK=G
//SYSIN    DD DSN=PGOS.BASE.DB2DATA&BNK.(UIGTMP01),DISP=SHR

The PDS name resolves to PGOS.BASE.DB2DATAG and the member UIGTMP01 is literal.

Creates:

{
    "dependencyType": "Control card; Resolved Symbol",
    "name": "UIGTMP01",
    "properties": {
        "JCL.PartitionedDataSet": "PGOS.BASE.DB2DATAG"
    },
    "path": "PGOS.BASE.DB2DATAG/UIGTMP01",
    "type": "CTL"
}

Symbolics in both PDS and member:

// SET TLQ=
// EXEC MYPROC,SYSTEM=SUB1

In the PROC:

//SYSTSIN  DD DSN=PGOS.&TLQ.BASE.DB2DATAG(&SYSTEM.DSN),DISP=SHR

The empty &TLQ collapses the double period: PGOS..BASE.DB2DATAG → PGOS.BASE.DB2DATAG. The member &SYSTEM.DSN resolves to SUB1DSN.

Creates on the calling JCL:

{
    "dependencyType": "Control card; Resolved Symbol",
    "name": "SUB1DSN",
    "properties": {
        "symbolic": "&SYSTEM.DSN",
        "JCL.PartitionedDataSet": "PGOS.BASE.DB2DATAG"
    },
    "path": "PGOS.BASE.DB2DATAG/SUB1DSN",
    "type": "CTL"
}

Edge cases

  • Unresolvable symbols: a symbolic parameter that has no value anywhere (no SET, no EXEC override, no PROC default) is left as written in the dependency name. The dependency is still reported, as "Missing Dataset", "Missing PDS" or "Missing Program", and its symbolic property keeps the original expression. In the PROC below &VAR1 is set by the calling JCL but &VAR3 is not:

    //SETVAR   SET VAR1=HELLO
    //JSTEP010 EXEC PROC1
    //PROC1    PROC DCLAS=DSIZE500
    //SYSUT1   DD DSN=&VAR1.XX.&VAR3.XXXXXXX.FILEDATA,DISP=SHR

    Creates on the calling JCL:

    {
        "dependencyType": "Read Dataset; Resolved Symbol",
        "name": "HELLOXX.&VAR3.XXXXXXX.FILEDATA",
        "path": null,
        "type": "Missing Dataset",
        "properties": {
            "symbolic": "&VAR1.XX.&VAR3.XXXXXXX.FILEDATA"
        }
    }
  • Empty symbolic values: If a PROC declares parameters with empty default values and the calling JCL does not override them, the symbolic resolution produces an empty value which appears as <<empty symbolic value>> nodes in the dependency graph. This also occurs for the concatenation of blank symbolic parameters, like &VAR.&VAR2.
  • Dynamic names (%%): Values containing %% (system symbols) are treated as dynamic and are not resolved.
  • Temporary datasets (&&): Double-ampersand names (e.g., &&TEMP) are temporary datasets and are not treated as symbolic parameters.
  • Chained symbolics: A variable whose value itself contains & is resolved iteratively until no more substitutions are possible.