Raincode Crossbow
Raincode Crossbow is a consistent release of the entire Raincode product line, covering compilers, emulators and ancillary tools.
In practice, Raincode Crossbow is designed with three driving forces:
-
A focus on performance across the board:
-
The internal computation engine for non-binary numeric data types (display numeric or packed decimals) has been entirely overhauled, resulting in performance improvements that can go up to a factor of 5 (depending on the level of dependence on these non-binary data types)
-
The file I/O layer has been optimized to ensure the best possible performance when dealing with indexed or sequential files
-
RadaR is a revolutionary solution to run batch steps 5 to 10 times faster, without changing the application source code or even the JCL they are called from
-
The Visual Studio plugin now runs the heaviest debugging operations asynchronously, thereby dramatically improving response time and the overall user experience, even when debugging programs with hundreds of active variables
-
The views generated to access VSAMSql and IMSql data using plain SQL DML statements have been optimized dramatically
-
-
Updated .NET platform support running both on Linux and on Windows, on virtual machines or in containers, on the cloud, on laptops or servers managed on premise.
-
Consolidation of the product suite, allowing all Raincode software to be built and upgraded synchronously, thereby avoiding the headaches that come from multiple products that follow different (and sometimes, incompatible) release cycles.
Version 6.0
In addition to the above description, Raincode Crossbow v6.0 (see release notes) is a technical release that includes the following:
-
Support for .NET 10.0 and SQL Server 2025 across the board.
-
The Visual Studio plugin now supports Visual Studio 2022 and 2026, with improved support for JCL debugging.
-
Support for the File-AID JCL utility.
-
Support for TLS encryption on QIX and IMS TN3270 terminal servers.
-
Removal of support for .NET Framework and .NET 6.0.
-
Removal of support for Microsoft Host Integration Server (HIS) for Db2.
-
Removal of 32-bit support.
1. Introduction
Raincode JCL executes z/OS’s Job Entry Subsystem (JES) mainframe JCLs with the same behavior, so that batch environments can be rehosted without requiring changes to the existing JCLs. It includes:
-
A JCL interpreter, that recognizes all the idiosyncrasies supported by JES on the mainframe
-
A comprehensive set of the most commonly used JCL utilities, that mimic the behavior of their mainframe counterparts
-
More specifically, among these utilities, Raincode JCL includes a high-performance sorting engine that can be used to sort even the largest data files efficiently
-
A comprehensive API to allow for the development of bespoke JCL utilities
-
Sample utilities provided in complete and compilable source form.
On the other hand, Raincode JCL does not include a scheduler. It is designed to be compatible with all third-party schedulers available on the market.
Raincode JCL is also designed to be programmatically customized, extended and integrated. Because of this flexibility through code, the intended audience of this document is twofold:
-
The operations staff, who need to be able to install, configure, operate and troubleshoot Raincode JCL
-
The development team, who want to go the extra mile, and change the behavior of Raincode JCL by means of its numerous programmatic interfaces.
The structure of this document reflects this duality. After this introductory chapter, which is targeted for both operations and development staff, the document is split into two parts. The first part primarily targets operations, describing how to work with the different parts of Raincode JCL. The second part exclusively targets the development team, explaining how to customize and extend Raincode JCL through code.
| Readers of the second part should obviously be familiar with the core elements laid out in the first part, as it describes the functionalities that they will be extending and customizing through code. |
As shown in the figure above, Submit.exe is the executable entry point to Raincode JCL. In turn, it relies on a number of components, namely the catalog manager, the parser and the batch runtime; each of which is further divided into multiple smaller modules.
For simplicity, this document will refer to the entry point of Raincode JCL as Submit.exe, even though it will be named Submit.dll when running on Linux, to be started by a command such as dotnet Submit.dll.
|
The default installation directory for Raincode JCL on Windows, depending on the version, is C:\Program Files\Raincode\JCL\net10.0 or C:\Program Files\Raincode\JCL\net8.0. The environment variable %RCBATCHDIR% points to the directories holding the different executables, including Submit.exe. The location of the catalog, utilities, and logs are configurable (see section Catalog configuration) for more details.
|
1.1. Submit.exe
Submit.exe is the equivalent of the mainframe’s SUBMIT command, which allows users to submit a JCL for execution. This can be achieved by starting Submit.exe on the command-line, or programmatically by calling the SubmitRunner.Execute() method.
All the coordination with the filesystem, launched processes, the interactions with the catalog, and the entire processing of a JCL is encapsulated in the call to Submit.exe. This design allows horizontal scaling by running jobs from different servers without a central coordinating server. The return code of Submit.exe is the highest return code of all the steps of the job for easy reporting and integration with schedulers. Editing the .NET configuration file for Submit.exe allows for custom configuration of various interfaces that provide extensibility.
For a complete description of the command-line options available for Submit.exe, please refer to Submit. The most straightforward way to execute Raincode JCL is to call Submit.exe by providing the JCL to execute with the -File option:
After execution, the resulting logs are stored in C:\ProgramData\Raincode\Batch\SYSOUT, as shown in the example below:
1.2. Catalog manager
Raincode JCL’s catalog manager emulates the catalog manager of the mainframe file system. It maintains its configuration information in an XML file, which is found by default in C:\ProgramData\Raincode\Batch\Raincode.Catalog.xml(shown in the figure below).
The default volume location for data sets managed by the catalog manager is C:\ProgramData\Raincode\Batch\DefaultVolume, as illustrated in the figure below.
The catalog manager can be accessed programmatically by developers. Internally, it relies on three subsystems, namely the data file manager, the lock manager and the file system support layer.
-
The data file manager handles the correlation for files (datasets) between the program and JCL for each step. Data files are represented by dataset objects, which describe the record layout and other information required for running job steps.
-
The lock manager obtains and releases the necessary locks on datasets when used by JCLs. These locks depend on the SHR option specified on the DD card. When running on Windows, locks are performed using the Win32 API function LockFileEx to lock a portion of the metadata file. This mechanism supports locking across network file shares and coordinates access between simultaneously running jobs.
-
The file system support layer is responsible for performing the physical I/O operations when reading, updating and writing files.
For more information on Raincode’s approach to handling datasets, please refer to Representation of the datasets.
1.3. The parser
The JCL parser is an internal component of Raincode JCL, which is irrelevant to the day-to-day use of the tool, but which can prove very useful for programmatic interaction with the product. This parser takes the JCL and builds an internal representation, that can then be used to process and execute it. The JCL parser includes support for two levels of preprocessing (performed before actually building the internal representation), namely AutoEdit preprocessing and JCL preprocessing.
The AutoEdit preprocessing phase partially mimics a functionality provided by Control-M. It includes date processing, where calendar files can be specified in the Control-M format or programmatically through the IAutoEditCalendar interface. Variables can be set externally using an environment variable CTM_xxxx, where xxxx is the AutoEdit variable name.
In the JCL preprocessing phase, %%SET statements and &VARIABLE references are supported, similar to how they are processed on the mainframe.
| The JCL parser may be accessed programmatically by developers, to allow for the input JCL stream to be altered at various stages of the processing by using the IJclPreprocessor interface. |
1.4. Batch runtime
The batch runtime is responsible for the different steps in executing a JCL. The basic flow of execution involves scanning, executing and cleanup, as illustrated in the figure below.
The process flows is as follows:
-
The JCL is scanned once, the intermediate representation is built, and execution is started.
-
The job execution process goes through the steps one by one, and checks for all the conditions that control their execution.
-
The step execution process is then responsible for executing one step in a given JCL. If needed, it will use the runner (see rclrun.exe) to run the executable program for that step. Alternatively, for a selected subset of the utilities, Raincode JCL allows for the execution to happen in-process, thereby avoiding the overhead of writing intermediate files, starting a subprocess, etc. and significantly improving performance.
-
The step cleanup process is executed at the end of each step execution, dealing with matters such as releasing datasets no longer used in the following steps.
-
-
Finally, the job cleanup process is executed at the end of each JCL.
When the runtime looks for a program to execute, it looks successively in the paths defined by:
-
STEPLIB, as defined in theJCL(STEPLIBcan be specified for all the steps or for one step only) -
JOBLIB, as defined in theJCL(JOBLIBis generally specified for the entireJCLand is defined before the first step) -
The default location, defined in the catalog definition.
-
The current directory where
Submit.exeis called from.
Programmatically, the batch runtime consists of an in-memory object model representing a JCL job and classes that facilitate the execution of steps. The parser builds up this in-memory job representation, and the Submit runner calls the Scan() and Execute() methods on the job to direct the process.
The entry point into the Scan/Execution facility is Raincode.Batch.Submit.SubmitRunner, which is contained in the Submit.exe executable. The static Execute() method can be called with options that specify an actual file to parse into a Job object and execute or a pre-built Job object.
|
1.5. The runner
Programs compiled by Raincode’s COBOL, PL/I, HLASM and zTrieve compilers cannot be executed directly from the command-line. They require a runner, an executable program that sets up the entire environment (memory, I/O, database connection, etc.) before actually executing the program.
The default runner is %RCBIN%\rclrun.exe. In the spirit of flexibility and extensibility, Raincode JCL (and the entire Raincode toolset) allows for the definition and usage of specialized, user-defined runners, to be used instead of the default one. In practice, this means that Submit.exe and the IKJEFT01 utility go through the runner to execute a compiled module, and leverage rclrun.exe to run these DLLs.
By default, the runner will search for the RCDIR environment variable and execute from the given path. If the RCDIR environment variable is not set, it will execute in the current directory.
The default runner can may be overridden in such a way that a user-defined runner is used instead. This is done by successively trying the following steps:
-
The content of the
RC_LegacyRunnerenvironment variable -
The content of the
LegacyRunnerenvironment variableLegacyRunner -
The content of the catalog configuration XML entity
legacyRunner
When Submit.exe starts executing a program by means of a runner (the default one or a redefined version of it), the environment variable RC_LegacyRunner is set to the path of the runner that is actually used.
2. Mainframe file system emulation
Mainframe datasets are stored in Windows or Linux files. These files are managed by the catalog system, emulating the mainframe file name structure using the DSN and syntax. In the Raincode catalog, a separate directory is created for each qualifier part of the DSN (qualifiers are separated by periods). Because the underlying file system cannot natively treat mainframe dataset attributes such as, e.g. record format and record length, datasets are stored as two files: one with a .meta and one with a .seq extension. The metadata of the dataset will be stored in the file .meta, and the data itself will be stored in .seq.
For example, consider the DSN XXX1.XXX2.FILE1. Inside the directory XXX1, there is a subdirectory XXX2, and the rightmost part of the DSN (FILE1) yields the files FILE1.seq and FILE1.meta in the subdirectory.
In addition to plain datasets, Raincode also provides native support for Partitioned datasets and Generation data group. These are stored as directories, with a special extension (._dir) to distinguish them from other folders.
2.1. File system emulation with an example
An example shows how the Raincode catalog emulates the mainframe file system. Refer to the following structure of datasets on the mainframe (also shown in Figure Datasets on mainframe):
-
RAINCODE.PROJECT1: High-level qualifier.
-
PDSTEST: Partitioned dataset.
-
GDMODEL1: Plain dataset.
-
GDGROUP1: Generation data group dataset.
-
GDGROUP1.G0001V00 and GDGROUP1.G0002V00 are the two files (versions) of the GDG dataset.
-
G0001V00 is version 1.
-
G0002V00 is version 2. (current version)
-
On Windows, this yields the following structure (also shown in Figure Datasets on windows):
-
Two qualifiers (Folders):
-
RAINCODE
-
PROJECT1
-
-
Two directories for PDS and GDG (._dir):
-
GDGROUP1
-
PDSTEST
-
-
File Dataset:
-
GDMODEL1
-
2.1.1. Partitioned dataset
A Partitioned Dataset (PDS), contains one or more members. These members are separate from each other. This structure is illustrated in the figure below.
In Windows, this gives the following structure: PDSTEST._dir, which contains MEM1 and MEM2, as shown in the figure below.
2.1.2. Generation data group
A Generation Data Group (GDG), is the versioning of one dataset that is successive generations of historically related data. This structure is illustrated in the figure below.
In Windows, this gives a structure where the directory contains the two versions of the GDG: G0001V00 and G0002V00, as shown in the figure below.
2.1.3. Metadata
In mainframe, metadata is stored in the catalog, for example, the metadata of RAINCODE.PROJECT1.PDSTEST is illustrated in the figure below.
The metadata for the same file on windows is as follows:
<dataSet
name="RAINCODE.PROJECT1.PDSTEST"
copies="0"
isCataloged="TRUE"
createDate="02/11/2020 09:41:47"
dataSetType="PDS"
expireDate="12/31/9999 23:59:59"
fileFormat="EntrySequenced"
markForDeletion="FALSE"
recordFormat="FB"
recordLength="80"
>
<FileConfig></FileConfig>
</dataSet>
2.2. Concatenated Datasets
On a mainframe, a JCL can specify a concatenated dataset; multiple datasets that are presented to the program as a single concatenation, for example, as follows:
//STEP4 EXEC PGM=DUMPCBL
//OUTFILE DD DSN=MYDATA.SAMPLE.RESULT,DISP=(NEW,CATLG),
// SPACE=(TRK,(5,5)),LRECL=80,RECFM=FB
//INFILE DD DSN=MYDATA.SAMPLE.FILE3,DISP=(OLD,CATLG)
// DD DSN=MYDATA.SAMPLE.FILE2,DISP=(OLD,CATLG)
// DD DSN=MYDATA.SAMPLE.FILE1,DISP=(OLD,CATLG)
Raincode JCL has two ways to represent concatenated files: logical concatenation (the default) or concatenating into a temporary file.
There are two ways to control the choice of whether or not to use temporary files for concatenated datasets:
-
Globally: by the usage of the Submit parameter
UseTempsForConcatenate=true|false -
For one specific program: by creating a .rcexe description (refer to
.rcexefiles) and include a tag `< UseTempForConcatenated>true|false</UseTempForConcatenated>
| The specific configuration overrides the global configuration. |
Further, these two approaches are explained in more detail.
2.2.1. Using logical concatenation
Raincode JCL and runtime (COBOL, PL/I, and HLASM) have logical concatenation as a default. When a concatenated dataset is declared, the Submit command passes a list of the data files to the program. The runtime system of Raincode can transparently read from the different files of the concatenation as needed.
In sample, the DUMPCBL program will receive DD_INFILE=MYDATA/SAMPLE/FILE3.seq;MYDATA/SAMPLE/FILE2.seq;MYDATA/SAMPLE/FILE1.seq
The significant advantage of this approach is that additional disk space or CPU time is not required to create a concatenated temporary file. The disadvantage is that the executed program must know and manage that list convention. This applies to any Raincode program but may not be apply to third-party tools.
2.2.2. Using a temporary file
The alternate approach is creating a temporary file to concatenate data into one file. Then, that single file will be passed as a parameter for the INFILE DD.
The advantage is that any called program sees only one input file for any DD, while the disadvantage is that the temporary file needs disk space and time to build.
2.3. Dataset Migration
This section explains migrating datasets from the mainframe to the Raincode catalog.
2.3.1. Transferring Datasets
To transfer a given dataset from the mainframe, use FTP in binary mode. If the dataset Variable Block (VB), ensure to use literal site RDW to transfer the Variable Record Descriptors, e.g.:
ftp mainframe.mycompany.com
ftp> binary
200 Representation type is Image
ftp> literal site RDW
200 SITE command was accepted
ftp> get MYFILE
2.3.2. Sequential dataset
To migrate a sequential dataset, follow these steps:
-
Transfer the file from the mainframe to the target machine, as described above in the section Transferring Datasets
-
Write a JCL to copy the recently transferred file into the catalog using the IEFBR14 utility. Ensure that the correct file attribute (
LRECLandRECFM) is given. For example:
//LOAD3 EXEC PGM=IEFBR14
//DD00 DD DSN=GRP.GMINI$10.MGAA1,
// DISP=(NEW,CATLG,DELETE),
// DCB=(LRECL=80,BLKSIZE=27920,RECFM=FB),
// PATH=('C:\myfile',COPY)
2.3.3. VSAM dataset
To migrate a VSAM dataset, follow these steps:
-
On the mainframe, copy the data from the VSAM file to a sequential one
-
Migrate the sequential dataset, as described above in the section Sequential dataset
-
Write a JCL to create the empty VSAM file. For example:
//STEP003 EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DEFINE CLUSTER (NAME(DATA3.ACCOUNT) INDEXED -
RECORDSIZE (80 80) -
KEYS (19 0) ) -
DATA (NAME(DATA3.ACCOUNT.DAT)) -
INDEX (NAME(DATA3.ACCOUNT.IDX))
-
Write a JCL to copy the temporary sequential file into the VSAM one. For example:
//STEP004 EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SORTIN DD DSN=TEMP.VSAM,DISP=SHR
//SORTOUT DD DSN=DATA3.ACCOUNT,DISP=SHR
//SYSIN DD *
REPRO IFILE(SORTIN) OFILE(SORTOUT)
2.3.4. Importing a line separated file into an Fixed Block dataset
Sometimes, Raincode receives ASCII line separated files, but these files need to be cataloged as a Fixed Block (FB) dataset. This is generally not a good idea; Raincode prefers receiving files in a binary (EBCDIC) format.
However, Raincode has a special dataset type call LSEQ, a dataset where an ASCII line feed separates each record.
To migrate a line separated file into an FB dataset, you can follow the following steps:
-
Copy the file into the catalog using the IEFBR14 utility. The RECFM should be LSEQ.
//STEP1 EXEC PGM=IEFBR14
// DD DSN=A.B,
// DISP=(NEW,CATLG,DELETE),
// DCB=(LRECL=252,RECFM=LSEQ),
// PATH=('C:\myfile',COPY)
-
Copy the LSEQ dataset into an FB dataset using IDCAMS
//STEP2 EXEC PGM=IDCAMS
//INF DD DSN=A.B,DISP=SHR
//OUTF DD DSN=A.C,
// DISP=(NEW,CATLG,DELETE),
// DCB=(RECFM=FB,LRECL=252)
//SYSIN DD *
REPRO INFILE(INF) OUTFILE(OUTF)
/*
2.3.5. Continuation in JCL
A JCL line cannot exceed 72 characters. However, Windows and Linux file paths can be much longer. To handle this, you can split the path across two lines. The second line should not begin with //, but must start with at least two spaces.
// PATH=('c:\a\very\lonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
g\path.txt',COPY)
2.4. ASA print file vs ASCII print file and LSEQ vs VLSEQ
On the mainframe, print files are stored in FBA files using the ASA printer control character as the first character in the record.
Usually, these files are produced by the report writer of COBOL programs that will use WRITE ADVANCING statements.
On the other side, windows and open system printers do not understand the ASA control char, and therefore, printing the resulting FBA requires a conversion. It is worth considering whether to use line sequential or variable line sequential files.
Below are the various aspects of handling print files.
2.4.1. Change the RECFM of the target file
Let’s suppose the following JCL step:
//STEP001 EXEC PGM=COB001
//RPT01 DD DSN=A.B,DISP=(NEW,CATLG,DELETE),LRECL=133,RECFM=FBA
where COB001 produces a report in the A.B file, this will generate an FBA file containing an ASA character, a first character and 132 printable characters per line.
If you replace RECFM=FBA with RECFM=LSEQ
//STEP001 EXEC PGM=COB001
//RPT01 DD DSN=A.B,DISP=(NEW,CATLG,DELETE),LRECL=133,RECFM=LSEQ
The produced file A.B will be an ASCII print file where controls use LF/CR/FF, which are ASCII control characters. The LRECL should not be changed as LSEQ will include 132 printables and 1 LF character at the end of the record.
The produced files are not FBA-compatible. Typically, the number of records will be greater, and the structure of the record is different. Therefore, this solution may only be used if the produced file is printed as-is, and no other program needs to read and process the result while assuming it is an FBA.
|
2.4.2. Convert the FBA to an ASCII print file using IDCAMS
In some cases, the change of RECFM is unacceptable because further steps use the produced file to read it and process or add other information. Changing the format may break the logic, and the JCL has a chance to fail.
Another solution is to convert the FBA ASA print file to the LSEQ ASCII print file at the end of the job. To do so, use IDCAMS REPRO utility with the CONVERT verb:
//STEP001 EXEC PGM=COB001
//RPT01 DD DSN=A.B,DISP=(NEW,CATLG,DELETE),LRECL=133,RECFM=FBA
…
//STEP04 EXEC PGM=IDCAMS
//INF DD DSN=A.B,DISP=SHR
//OUTF DD DSN=A.C,
// DISP=(NEW,CATLG,DELETE),
// DCB=(RECFM=LSEQ,LRECL=133)
//SYSIN DD *
REPRO INFILE(INF) OUTFILE(OUTF) CONVERT
/*
In STEP04, the IDCAMS REPRO utility, using the CONVERT command, reads the FBA file and converts ASA characters to output the equivalent file as an ASCII print file.
CONVERT only works if the input file is an FBA, VBA, FBM or VBM file and the target is an LSEQ or VLSEQ file.
|
2.4.3. LSEQ or VLSEQ
To handle print files, Raincode supports two line sequential files that are usable in RECFM.
-
LSEQis a fixed record size line sequential. The record is fixed size padded with space, and the last character is anLF(ASCII Line Feed ). -
VLSEQis a variable record size line sequential. The record is variable size trimmed: all trailing space is removed, and the last character is anLF(ASCII Line Feed). UnlikeVBfiles, no size is written at the beginning of the record. The size is computed when the firstLFis read.
3. Submit
This section describes the relevant workings of Submit, the equivalent of the mainframe’s SUBMIT command, allowing users to submit a JCL for execution. In the beginning, various aspects of its use are described, and the end of this section contains the list of current command-line options for Submit.exe (as generated by Submit.exe itself).
3.1. Resolution of PGM=xxx
Each step of a JCL that includes PGM=<name> requires Submit to map the name to an external program to execute. To do so, Submit performs a lookup for a filename in the form <name>.<extension>, in the order of the following table:
EXTENSION |
FILE TYPE |
REMARK |
|
|
See |
|
|
|
|
|
|
|
|
|
|
` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Submit looks for the file in the directories in the order listed in the following table.
LOCATION |
REMARK |
STEPLIB |
The path defined in the step’s STEPLIB, if defined |
JOBLIB |
The path defined in the JCL’s JOBLIB, if defined |
Executable Search Paths |
The path list defined in the attribute |
submit.exe path |
The path of the running |
JCLLIB |
|
Current working directory |
The current working directory of the |
3.1.1. .rcexe files
The execution of a program in Raincode JCL is controlled by files with the .rcexe extension, which provides meta-data that controls how the program is to be executed. Among other capabilities, this allows one to redirect the execution of any given program to alternate executables. This .rcexe file is an XML file.
The root element of the file is an RCLaunch element, and it may contain a number of child elements. All of these child elements are optional.
The type of XML elements allowed in a .rcexe file are described in the following table:
| XML ELEMENT | DESCRIPTION |
|---|---|
ExecutablePath |
The full path to the executable is specified here. If the |
Arguments |
The arguments that are passed to the executable when it is called. |
WorkingDirectory |
This is a working directory; if it is not specified, the directory used will be the same as the one for |
ParametersAsEnvVar |
Are the parameters PARM=(…) only passed as environment variables in |
ExecMode |
Execution Mode:
|
UseTempForConcatenated |
Use temporary files for concatenated DDs (see the section on Concatenated datasets) |
Alias |
This command is just an alias of the name provided. For Example, If an alias is present, no other elements are needed. This alias itself will represent the command that is actually executed. |
DisableSysoutRedirect |
Disables the capture of When false, When set to true, |
DisableSyserrRedirect |
Same as |
For example, the file below specifies that the program name Myprog is mapped to the windows program c:\somepath\myexec.exe, and it will use temporary files for concatenation.
<?xml version="1.0" encoding="utf-8" ?>
<RCLaunch>
<ExecutablePath>c:\somepath\myexec.exe</ExecutablePath>
<UseTempForConcatenated>true</UseTempForConcatenated>
</RCLaunch>
3.1.2. Treatment of dll files
If Submit encounters a .dll, it is supposed to be a .Net assembly. Submit inspects the assembly to determine if it contains a Raincode legacy signature (e.g. it is generated by a Raincode legacy compiler).
If the legacy signature is found, Submit will use the runner to execute the DLL. If the signature is not found, the DLL will be executed using the dotnet(.exe) command-line utility.
3.2. Job Scheduler Integration
To allow integration with an external scheduler, Submit.exe returns the return code of the job that it executes. Therefore, to integrate with a job scheduler application, follow the instructions for executing a console application and use Submit.exe as the executable.
3.3. Job outputs
By default, the job outputs, i.e. the contents of SYSOUT for a job, are located in the C:\ProgramData\Raincode\Batch\Sysout directory. Each job that has been executed will have a specific folder containing the SYSOUT info.
Each folder in SYSOUT will contain the following:
-
MSGLOG: The standard output from running a job. -
SYSLOG: Job information, job step statistics, and over job statistics display. -
SPECIFIED STEP: Specific sysout as defined by the job JCL. -
JCL LISTING: JCL for the job being run. -
StepActivity.json: Detailed information regarding the step activities of a job. They are used for restart. -
StepDDActivity.json: Detailed information regarding the DDs of each step of a job. They are used for restart.
3.4. JCL job repository
Submit includes the ability to build a database repository that archives several tables of the submitted JCL job, like job steps, conditions, procedures, etc. This repository can be used to analyze the portfolio and estimate the required workload for a migration effort.
Repository generation is only available when the -ScanOnly option is used along with the -DBDriver and -DBConnectionString command-line options. The DBDriver options specifies the desired type of database driver, and DBConnectionString specifies the desired connection string for the database.
The first database driver that can be used is SQLite, e.g., as follows:
Submit.exe -File=.\JOB.JCL -ScanOnly -DBDriver=Sqlite
When using SQLite as the database driver, the repository will be created in the same directory where Submit.exe is executed under the default repository name: RC_JCL_INVENTORY.db. However, one can specify the name of the database file through the DBConnectionString option.
Alternatively, an ODBC driver can be used, e.g., as follows:
Submit.exe -File=.\JOB.JCL -ScanOnly -DBDriver=ODBC -DBConnectString="DSN=odbcConnect"
When using the ODBC driver, the target database is an SQL Server. On the server side, one needs to create a database named: RC_JCL_INVENTORY and define the ODBC data source for the connection before executing Submit.exe. This data source needs to be passed as part of the DBConnectionString option.
The created repository includes several SQL tables giving viable information about the submitted jobs. For more details, refer to the appendix JCL JOB repository.
3.5. JCL dataset Locking
Raincode JCL emulates the locking mechanism of mainframe JCL on datasets using two-step lock file acquisition. Therefore, no changes must be made to the JCL batches to work with Raincode JCL. In order to prevent deadlocks, locks are obtained upfront at the beginning of the job, and taken in alphabetical order based on DSNAME.
3.5.1. Locks and the file system
Recall that Raincode JCL represents each dataset by a pair of files: the data file (.seq), and the meta file (.meta), as described in the Mainframe file system emulation. When a lock is obtained on a dataset, Raincode JCL will only lock the meta file.
The lock files are located in a special directory structure that exists for each volume defined in the catalog. This structure includes a directory named _lock, which is a subdirectory of the volume’s root. To lock a dataset, lock files will be placed in the _lock directory.
The _lock directory is not addressable via JCL and should only contain lock files.
|
Spurious locks, i.e. files being considered locked when they are not, can be removed by removing the corresponding lock files in the _lock directory. Alternatively, all locks can be removed by deleting the _lock directory.
|
The locking mechanism is also accessible programmatically. When developing utilities that involve catalog manipulation, developers should use the lock facilities by referencing the Raincode.Batch.LockingClient assembly and using its exposed interface. Similarly, when developing applications not called from a JCL but still interacting with the catalog, the developer needs to take care to lock and unlock files that will be accessed. This can be done using the LockingManager static methods from the Raincode.Batch.Catalog assembly.
3.5.2. Implementation of Locking
Raincode uses a lock file system as a semaphore to manage locking on the meta file. There are two lock files for a meta files: the shared lock file (.ls) and the exclusive lock file (.le).
The shared lock file represents that a process has a shared lock on a dataset. The exclusive lock file is the semaphore to the shared lock file, and both represent that an exclusive lock is owned or that a file is in the process of acquiring a shared lock.
The main principle is that all lock manipulation follows a two-step process (as illustrated in the figure Locking process):
-
Obtaining a lock to exclusively lock the exclusive file.
-
Once the lock on the exclusive file is obtained, try to acquire a lock on the shared file. The lock will be exclusive or shared, depending on the JCL level of locking needed.
Using the OS-provided locking mechanism removes the need for complicated bookkeeping by avoiding modifications to the files. All file opening are performed with a Delete on Close mechanism, usually provided by the operating system.
3.6. Command-line options for Submit.exe
Below are the details of the command line options of Submit.exe. These tables are automatically generated and contain the same information produced by running Submit.exe without arguments.
Debugger
| Command-line option | Default value | Description |
|---|---|---|
|
|
Will launch JCL interpreter with the ability to attach JCL debugger later. |
|
|
Will launch JCL interpreter attached to JCL debugger. this is to enable JCL programs debugging (should only be used by IDEs or Debugger developers) |
|
|
IP Address of host where JCL debug server will get hosted at, localhost will get used by default |
|
|
TCP port of JCL debug server, (default = 9090) |
General
| Command-line option | Default value | Description |
|---|---|---|
|
This command-line option enables calls to Raincode utilities to be performed in-process without the performance penalty of spawning a new external program. This option will only apply to some of the predefined utilities delivered together with Raincode JCL. |
|
|
Specifies the path to the configuration file for the catalog. If the option is not specified, |
|
|
|
This command-line option emulates the Control-M NCT2 function. RCS801 is the error code. Duplicate datasets will be cleaned at restart. |
|
This command-line option lets users define comments that |
|
|
|
Enables Control-M support. See also the EnhGDG and CM_NCT2 command-line option. |
|
|
If this command-line option control is enabled, Raincode JCL checks the presence of space parameter for DD with DISP=NEW/MOD. This is used for strict mainframe compatibility. |
|
Specifies the name of the step to debug. It causes a JIT debugger breakpoint to trigger when the step with a matching name is being executed. |
|
|
|
Triggers a JIT breakpoint at the start of the |
|
|
This command-line option forces the preprocessing of any JCL to start a state equivalent to %%RESOLVE(OFF). |
|
|
Allows a disposition DISP=SHR to refer to a non-existing file, which will then be created on the fly. |
|
Indicates the log level required from the runner (rclrun or other) when executing compiled COBOL, PL/I, HLASM or zTrieve programs. |
|
|
Fully qualified dataset name for the JCL file to |
|
|
Enable to store MetaFileInfo inside the DD information (default= true) |
|
|
|
Enables file I/O caching between steps. |
|
|
Enables meta file caching between steps. |
|
Enable meta file flush(true) (default= false) |
|
|
|
Enables the emulation of Control-M’s support for GDG adjustment at restart. |
|
|
(Linux Only) Enables case-insensitive matching when looking for a program. |
|
Path to a source file containing the JCL to submit. This command-line option takes a valid file name on the current operating system (as opposed to a catalogued DSN). It can prove useful for bootstrapping an installation since it allows for the execution of a JCL which is not in the catalog. |
|
|
|
Indicates that FileStream.Open should be used to test for a file’s existence. |
|
This command-line option provides a string to the JclConverter.xml configuration file. If this parameter is set, the given JCL will be translated into a new command format for the utilities. |
|
|
This command-line option lets the user define the Job ID when there is an external scheduler. |
|
|
Sets a different name to the job instead of using the default. In this case, the Job name on the job card is ignored. |
|
|
Keep info about Name of the step to restart the job with after execution of the first step |
|
|
|
Retains the temporary files created by Raincode JCL instead of deleting them. To be used for debugging. |
|
This command-line option registers a log file listener that displays the log to the console. |
|
|
This command-line option registers a log file listener that displays the trace data to the Windows log trace facility. |
|
|
|
Sets the MSGLOG.txt and SYSOUT logfile flushing interval, expressed in seconds. A negative value for this parameter causes this logfile not to be flushed. |
|
When using WRITE ADVANCING, use NoAdv if you already adjusted record length to include 1 byte for the printer control character |
|
|
|
Specifies the size of the pool of ports that can be used for tcp.net binding. |
|
|
This command-line option specifies the port number of the first port for tcp.net binding.P |
|
Specifies the directory where PROCs should be looked for if not defined in the catalog. |
|
|
Specifies the record format of the file to submit using the
|
|
|
Specifies the record length for the file to submit using the |
|
|
|
Release file locks at the step level. |
|
This command-line option specifies the connection string for the repository. See also the RepoDriver option. |
|
|
This command-line option sets the connection string for the repository persistence system as an ODBC connection string if ODBC persistence is used or as a physical file name if SQLite is used instead. See also the DBConnectString option. Valid values are:
|
|
|
Specifies the name of the step where the job must be restarted. It overrides the RESTART= parameter in the JCL if present. To restart on a proc-step, the format STEP1.MYPROC should be used. |
|
|
Specifies the job ID that the user is attempting to restart. The restart JobID refers to the JobID of the previous execution that needs to be restarted. |
|
|
Specifies the name of the final step of the JCL to execute. When a step with a matching name is encountered, it is executed, and the job is terminated. To specify a proc-step, the format STEP1.MYPROC should be used. |
|
|
Specifies the full path of SYSOUT folder. |
|
|
|
Activates the parsing and scanning of the JCL, disables any executions of the steps. This command is useful for checking a JCL for syntax and compatibility. |
|
|
Specifies the IP address for the server that provides the locking service to connect to if not on the same machine. |
|
|
Instructs the JCL interpreter not to output anything to the console. This does not affect the log. |
|
|
This command-line option does step profiling info in a separate file. |
|
Specifies the path to the XML file to be used for SUBSTVAR processing. This command overrides the setting in the catalog configuration for SubstitutionVariableFilePath. |
|
|
|
Activates the storage of the SYSLOG data in an XML format, with an XML extension. The file will be stored in the same directory as the SYSLOG (SYSLOG.<jobname>.TXT). |
|
|
Truncating the JCL input stream at column 72. This allows the JCL to contain line numbers or comments after column 72, that will be ignored. |
|
|
Requires the construction of a temporary file for the concatenated input. |
|
Specifies the log level to use when running Raincode utilities. |
|
|
|
Ensures that the user’s job ID has not already been used. If it is, the Job is stopped, and the return code is set to 16. |
|
If set, this command-line option specifies the volume where DSNs are stored. When a DSN is provided without specifying a volume, the default volume will be used. However, if the DSN is located on a different volume than the default, you will need to specify that volume as well. |
Miscellaneous
| Command-line option | Default value | Description |
|---|---|---|
|
This command-line option specifies the runtime’s time by initializing it with a specified datetime value, using an offset. The DateTimeOffset allows the offset to be specified instead of the initial datetime. |
|
|
This command-line option is an additional .net 'app.config' file. |
|
|
Checks and displays the current license. |
|
|
Displays the tool’s help information. |
|
|
||
|
|
Displays a description of the program. |
|
Specifies the date and time to use to give to the runtime, to be used instead of the system time. The format for this option is XXXXXXX. |
|
|
|
Specifies the log level. Valid values are:
|
|
|
Displays the version information. |
4. Catalog configuration
Submit relies on the catalog manager, among others, to perform its functions.
The catalog manager emulates the catalog manager of the file system on the mainframe, i.e. it implements a view on the emulated file system that is part of Raincode JCL. The catalog manager can be configured using the catalog configuration file. It allows users to change default settings, such as units, volumes, record length, etc.
When Submit begins, it looks for the catalog configuration in the following sequence:
-
If the command line option
-CatalogConfigurationis provided, its parameter specifies the path to the catalog configuration file. -
If the environment variable
RC_BATCH_CATALOGis set, its value is used as the path to the catalog configuration file. -
If neither of the above is set, the file in the default location
C:\ProgramData\Raincode\Batch\Raincode.Catalog.xmlfor Windows, or/var/lib/Raincode/Batch/ Raincode.Catalog.xmlfor Linux, is used.
If the lookup fails, a Default catalog configuration file will be created in the default location, and this file will be used.
4.1. Default catalog configuration
Below is the default configuration file (for Windows at the time of writing this document) created if the lookup fails. It consists of a top-level CatalogConfiguration element with several relevant attributes and various nested entities, all of which are described in the remainder of this chapter.
<catalogConfiguration
defaultRecordLength="80"
defaultSysoutRecordLength="133"
defaultSysprintRecordLength="133"
truncateRedirectedSysoutRecord="true"
ebcdicCompareCodePage="870"
defaultOutputClass="A"
defaultCodePage="1252"
sysoutFolderPath="C:\ProgramData\Raincode\Batch\SYSOUT"
sysoutVolumeName="#SYSOUT"
sysoutSyslogVersion="1"
noAdv="false"
sysoutMetaKeep="true"
ignoreUnitName="false"
strictCatalogValidation="false"
autoEditCalendarFolderPath="C:\ProgramData\Raincode\Batch\AutoEditCalendars"
sysoutFolderNamingPattern="JOB{ID}"
syslogNamingPattern="SYSLOG"
defaultRecordFormat="FB"
defaultSysoutRecordFormat="LSEQ"
defaultSysprintRecordFormat="LSEQ"
instreamDataRecordFormat="FB"
instreamDataRecordLength="80"
SDSN_Wait="3600"
enforceMemoryRestriction="true"
enforceUpdateLastReference="false"
enforceSMSValidation="false">
<units>
<unit
name="SYSDA"
isDefault="true">
<volumes>
<volume
name="DEFAULT"
path="C:\ProgramData\Raincode\Batch\DefaultVolume"
isDefault="true" />
</volumes>
</unit>
</units>
<defaultProcLibraries>
<DSN>::SYS1.PROCLIB</DSN>
</defaultProcLibraries>
<SysoutMetaKeep>true</SysoutMetaKeep>
<codePages
jclAlternate="1252"
jclRewrite="Default" />
</catalogConfiguration>
4.2. Catalog configuration description
The top-level CatalogConfiguration element can have several attributes, the meaning of which is described in the table below.
| Tags | Default Values | Description |
|---|---|---|
autoEditCalendarFolderPath |
"Configuration_folder\AutoEditCalendars" |
Path to the folder containing named calendar XML files. For more details, refer to the AutoEdit calendar configuration. |
batchCustomPluginPath |
Path to the folder containing the batch plugins. |
|
batchCustomPlugins |
Names of the plugins that are loaded when executing |
|
catalogDbConnection |
If |
|
catalogFormat |
disk |
This tag is the catalog storage format. The accepted values are |
dbConnectionDataProvider |
RcDbConnections.csv |
The path to the CSV file is provided to map the PLAN name to the actual connection string. For more details, refer to the section Map a PLAN name to a connection string. |
defaultAsciiCodePage |
The default code page for interpreting ASCII data. If nothing is set, the |
|
defaultCodePage |
1252 |
The default code page for interpreting text data. This is particularly useful for testing jobs that need to execute under a code page different from the current system. For more details, refer to the section, JCL character encoding. |
defaultEbcdicCodePage |
The default code page for interpreting EBCDIC data. For more details, refer to the section JCL character encoding. |
|
defaultFileConfig |
|
Default File Config parameters |
defaultOutputClass |
A |
The default output class for SYSOUT=*, if an MSGCLASS is not specified on the JOB card. |
defaultRecordFormat |
FB |
Default record format. At the moment, only |
defaultRecordLength |
0 |
The default record length, if not specified, should be set to 0. If set to 0, it will be changed to 80 |
defaultSysoutRecordFormat |
LSEQ |
The default record format for SYSOUT ( |
defaultSysoutRecordLength |
133 |
The default record length for SYSOUT datasets. |
defaultSysprintRecordFormat |
LSEQ |
The default record format for SYSPRINT ( |
defaultSysprintRecordLength |
133 |
The default record length for SYSPRINT datasets. |
directoryTypeExtension |
._dir |
Extension for directory type datasets. (Only used if catalogFormat is |
ebcdicCompareCodePage |
870 |
The EBCDIC code page to use for comparing strings. This is used by AutoEdit conditional processing statements. |
enforceMemoryRestriction |
TRUE |
This flag indicates whether or not a memory limit should be enforced for the process. Accepted Values: |
enforceUpdateLastReference |
FALSE |
Enforce that the lastReferenceDate will be updated at any access to the data file. Accepted values: |
instreamDataRecordFormat |
FB |
The default instream data record format, used if the JCL does not specify RECFM options. |
instreamDataRecordLength |
80 |
The default instream data record length, used if no DD parameters are set overriding the instream data record format in JCL. |
isamDefaultDriver |
Empty |
Allows you to specify the default driver used for ISAM (flat, non indexed) file. |
legacyRunner |
%RCDIR%/bin/rclrun.exe |
Path to the runner needed to run a COBOL, PL/I or HLASM program. This allows the use of a user-defined runner, as shown in the section Customizing Legacy Runner calls. |
legacyRunnerParameters |
Empty |
Add additional parameters when invoking |
SDSN_Wait |
"3600" |
Specifies the installation policy for batch jobs that must wait to enqueue the dataset (Locking). Values can be |
SMSConfig |
"Configuration_folder" |
Specifies the values of the SMS DD parameters ( |
substitutionVariableFilePath |
Optional path to a file containing substitution variables. For more details, refer to the section Substvar. |
|
sysoutFolderNamingPattern |
"JOB{ID}.{NAME}" |
Naming pattern to use when generating the SYSOUT folder name. For more details, refer to the section Sysout Folder Naming Convention. |
sysoutFolderPath |
"Configuration_folder\SYSOUT" |
Path to a folder where job-specific SYSOUT files should be written. |
sysoutMetaKeep |
TRUE |
If true, the SYSOUT meta file will be kept at the end of the step. |
sysoutSyslogVersion |
1 |
The version of the SYSLOG format in the SYSOUT folder. |
sysoutVolumeName |
#SYSOUT |
Name of the volume used to store SYSOUT files. |
truncateRedirectedSysoutRecord |
TRUE |
If true, truncate SYSOUT record to the length of SYSOUT when redirected to a file. |
vsamDefaultDriver |
Empty |
Allows specifying the default driver for VSAM Indexed files when using something other than the default ISAM. For example, set the value to VsamLite to store Indexed files in an SQLite database. |
The CatalogConfiguration element can have various nested entities, as described in the following table.
| Tags | Values | Description |
|---|---|---|
autoDDCardDefinitions |
Definition of DD cards for the step that is not explicitly declared in the JCL. For more details, refer to the section JCL Automatic DD card definition. |
|
datasetSqlMapping |
Datasets data that are stored into a database. For more details, refer to the section Dataset mapping with tables. |
|
defaultProcLibraries |
|
List of PDS libraries to search for PROCs. SYS1.PROC is always added as the last element. |
environmentVariables |
Environment variable values that Submit will set at the beginning of each step. For more details, refer to the section Environment Variables. |
|
executableSearchPaths |
Paths to use when looking for an executable in an EXEC statement. Each path is specified within a |
|
fileFormatExtensions |
|
List of file extensions for file formats, indexed by file format enum cast as int. |
noLocking |
List of DSN patterns on which locking must not be applied. The pattern is a simple IDCAMS pattern a.c.C.**. |
|
programDBConnectionDefinitions |
Define rules to associate programs and jobs to a default PLAN (by extension a connection String). For more details, refer to the section DB connection definition |
|
recordFormatExtensions |
List of file extensions for file types, indexed by file type enum cast as int. |
|
Units |
Units that are defined in the catalog. For more details, refer to the section Unit and Volume Configuration. |
|
codePages |
|
The default code page to use for interpreting ASCII data. This is particularly useful for testing jobs that need to execute under a code page different from the current System. For more details, refer to the section JCL character encoding. |
4.3. AutoEdit Configuration
Raincode JCL includes support for the expansions of Autoedit variables in JCLs. In addition to the use of autoedit datasets, as on the mainframe, it looks up environment variables to find values when needed. For example, if a variable such as %%FOO could not be found in an autoedit dataset, the value of the CTM_FOO environment variable (if present) will be used instead. Additionally, the values for some variables set by Control-M , listed below, need to be specified through environment variables before they can be used in the JCLs.
Parameter |
Environment variable passed by Control-M |
%%APPL |
CTM_APPL |
%%JOBNAME** |
CTM_JOBNAME |
%%ORDERID** |
CTM_ORDERID |
%%RN** |
CTM_RN |
%%TIME |
CTM_TIME |
%%$CENT |
CTM_$CENT |
%%DATE |
CTM_DATE |
%%DAY |
CTM_DAY |
%%MONTH |
CTM_MONTH |
%%YEAR |
CTM_YEAR |
%%WDAY |
CTM_WDAY |
%%ODATE |
CTM_ODATE |
%%ODAY |
CTM_ODAY |
%%OMONTH |
CTM_OMONTH |
%%OYEAR |
CTM_OYEAR |
%%OWDAY |
CTM_OWDAY |
%%RDATE |
CTM_RDATE |
%%RDAY |
CTM_RDAY |
%%RMONTH |
CTM_RMONTH |
%%RYEAR |
CTM_RYEAR |
%%RWDAY |
CTM_RWDAY |
%%JULDAY |
CTM_JULDAY |
%%OJULDAY |
CTM_OJULDAY |
%%RJULDAY |
CTM_RJULDAY |
%%$DATE |
CTM_$DATE |
%%$YEAR |
CTM_$YEAR |
%%$ODATE |
CTM_$ODATE |
%%$OYEAR |
CTM_$OYEAR |
%%$RDATE |
CTM_$RDATE |
%%$RYEAR |
CTM_$RYEAR |
%%$OJULDAY |
CTM_$OJULDAY |
%%JOBID |
CTM_JOBID |
Autoedit calendars are also supported. By default, they are read from the C:\ProgramData\Raincode\Batch\AutoEditCalendars path, but this behavior can be overridden by using the the autoEditCalendarFolderPath attribute in the catalog configuration.
The example configuration file below shows the expected structure of such a calendar file. The important part is the NAME= property since it maps to the calendar name that AutoEdit uses.
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE DEFCAL SYSTEM "defcal.dtd">
<DEFCAL>
<CALENDAR DATACENTER="enterprise" NAME="MYCALENDAR" TYPE="Relative">
<YEAR NAME="1999" DAYS="NNNNYYYYNYYYYYYYYNNNNYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYNYYYYYYYYYYYYYNYYYYYYYYYYYYYYYYYYYNYYYYYYYYYYYYYYYYYYYYYYY" DESCRIPTION="This is year 2000"/>
<YEAR NAME="2000" DAYS="YYNYYYYYNYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYNYYYYYYYYYYYYYNYYYYYYYYYYYYYYYYYYYNYYYYYYYYYYYYYYYYYYYYYYY" DESCRIPTION="This is year 2000"/>
<YEAR NAME="2001" DAYS="YYNYYYYYNNNNNYYYYYYYYYYNYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYNYYYYYYYYYYYYYNYYYYYYYYYYYYYYYYYYYNYYYYYYYYYYYYYYYYYYYYYYY" DESCRIPTION="This is year 2001"/>
</CALENDAR>
</DEFCAL>
Alternatively, the IAutoEditCalendar interface can be implemented and registered in the submit.exe.config file to perform the supported calendar operations. The default implementation uses the XML file format from Ctrl-M. It only supports the relative type format shown above.
4.4. Bootstrapping your Environment: An Example
Bootstrapping your environment typically consists of creating one or multiple PDS libraries and importing existing JCL files into the PDS libraries created. Below is an example of such a JCL bootstrap job.
//BOOTSTRAP JOBID
//*
//* This job is used to bootstrap the batch environment
//*
//* First we create the PDS Library
//STEP1A EXEC PGM=IEFBR14
//DD1 DD DSN=NIMBLE.TEST.JCL,DSNTYPE=PDS,
// DISP=(NEW,CATLG,DELETE),RECFM=LSEQ,VOL=SER=DEFAULT
//*
//* Second, we import the JCL files using a DD Path option
//STEP2 EXEC PGM=IEFBR14
//DD1 DD DSN=NIMBLE.TEST.JCL(CONDEXEC),DISP=(,CATLG,DELETE),
// PATH=('.\JCL\CONDEXEC.JCL',COPY)
//*
//DD2 DD DSN=NIMBLE.TEST.JCL(CONDJOB),DISP=(,CATLG,DELETE),
// PATH=('.\JCL\CONDJOB.JCL',COPY)
//*
//DD3 DD DSN=NIMBLE.TEST.JCL(DCBINFO),DISP=(,CATLG,DELETE),
// PATH=('.\JCL\DCBINFO.JCL',COPY)
//*
4.5. Running programs from JOBLIB and STEPLIB
When a JOBLIB or STEPLIB is specified in the JCL, Submit first searchesthe specified libraries for executables (for more details, refer to the Resolution of PGM=xxx) .
For this feature to function properly, it is necessary to define the corresponding libraries in the catalog, and load them with the program binaries (DLLs). You can create a PDS library (in this case named ENV.DEV) as shown below:
//CREATELIB JOB
//*
//STEP0 EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DELETE ENV.DEV
SET MAXCC=0
//*
//STEP1 EXEC PGM=IEFBR14
//DD1 DD DSN=ENV.DEV,DSNTYPE=PDS,
// DISP=(NEW,CATLG,DELETE),RECFM=LSEQ
Assuming that you have a COBOL source file named HELLO.cob, which has been compiled into HELLO.dll, the compiled file must be copied to the PDS library ENV.DEV, located at <default volume>\ENV\DEV._dir\.
At this point, the library is ready to be used. You can then create a JCL to execute a program from this library. For example:
//Hello JOB Hello, COND=(4,LT)
//STEP01 EXEC PGM=Hello
//SYSPRINT DD SYSOUT=*
//STEPLIB DD DSN=ENV.DEV,DISP=SHR
The resulting PDS library can, of course, be also used for JOBLIB.
4.6. Dataset mapping with tables
When using the VSAMSql, VSAMLite, and VSAMOracle drivers (see chapter VSAMSql), the dataset must be defined to use the VSAMSql driver to store data in a database instead of on the file system. This mapping information is stored in the <datasetTemplate> element under <datasetSqlMapping>.
The <datasetTemplate> element contains several attributes:
-
connection: the plan for the connection string, see section Map a PLAN name to a connection string -
tableName: the name of the table in which the data is stored. -
commitRate: the number of inserts to be done before a commit. If it is set to -1 (the default), the commit is only done when the file is closed. -
driver: the driver to be used. The default value is VSAMSql. -
cache settings: see the VSAMSql Cache configuration section for more information.
<datasetTemplate> contains one or more <pattern> elements, one <parameters> element, zero or one <partitions> elements and zero or more <driverParameter> elements.
An example is below:
<datasetTemplate tableName="REC_AREA" connection="VSAMDEAL">
<pattern>
<DSN>VSAM\.AREA\..*</DSN>
</pattern>
<pattern>
<volume>DEFAULT</volume>
<DSN>VSAM\.RECAREA</DSN>
</pattern>
<parameters length="316">
<key start="1" length="10"/>
<altKey start="305" length="5" unique="Y"/>
</parameters>
</datasetTemplate>
The different entities in the datasetTemplate entity are as follows:
-
<pattern>describes the dataset name that must be stored in the table. It contains at most one<volume>element that gives the name of the volume. Use the default volume if there is no<volume>element. It contains one<DSN>element, a regex representing the DSN stored in this table. -
<parameters>describes the maximum size of the records and their keys. The attributelengthis the maximum length of the records. The optional element<key>defines 0 based position (start) and the size (length) of the key. And zero or more elements<altKey>define the 0 based position (start) and the size (length) of the alternated key. Theuniqueattribute is set toYorYESif the alternate key is unique, otherwise it is set toNorNO. -
<partitions>describes the mapping between the file names and the partition number (see Partitions). It’s composed of one or more <partition> elements. The <partition> element contains the following attributes:-
id: the id of the partition
-
volume: the volume of the file
-
DSN: the DSN of the file (without wildcard)
-
-
<driverParameter>is used to give parameters to the driver. These additional parameters can be specific to a job, a step or a program. The additional parameters are conditional, based on a matching regular expression onProgram Name,StepId, andJobId. This is done through the definition of attributes ondriverParameter, all of which are optional. See the table below.
| Attribute name | Function | Type | Typical Value |
|---|---|---|---|
jobId |
Regular expression to be matched on the current Job ID |
Regular expression string |
00X1.. |
jobName |
Regular expression to be matched on the current Job Name |
Regular expression string |
TSK01.* |
pgm |
Regular expression to be matched on the current PGM=clause |
Regular expression string |
PRG001 |
stepId |
Regular expression to be matched on the current Step ID |
Regular expression string |
0001.* |
Considering the contents of driverParameter: it should be a valid XML and is passed to the file driver as it is. The VSAMSql allowed elements are:
-
connectionGroup: a group can be associated with a file. All the files that belong to the same group use the same DB transaction, i.e., all the tables storing the data are committed together. -
commitReadNext: if it is set to 1 for a file, each time a record of this file is read, the connection group to which this file belongs is committed. -
commitRate: the number of inserts to be done before a commit. If it is set to -1, the commit is only done when the file is closed. It overrides the value of the attribute of datasetTemplate.
In addition to the above mentioned parameters, cache configuration parameters can also be specified, as detailed in the VSAMSql Cache configuration section.
Tables creation
Before using the VSAMSql/VSAMOracle files, tables need to be created. VSAMLite creates the tables on the fly. The driver does not do the table creation because the people executing a program usually don’t have the right to create tables; that’s why there is a program, VsamSql.DbGenerator reads the catalog configuration and generates the table creation script (see Database creation). This script needs to be executed by somebody (DBA, for example) that has the right to create tables.
4.7. Dataset mapping for DSN to Volumes
If the volume (VOL-SER) is not defined in the DD statement, the dynamic distribution for files occurs as mentioned below.
The <defaultVolumeMapping> element contains the following attributes:
-
defaultVolume: contains two entries,
DSNandVolume -
DSN: the string that will be checked against the
DSNname. -
Volume: the
Volumename where the file will be stored. For this entry, a UNIT definition must exist.
An example is illustrated below:
<defaultVolumeMapping>
<defaultVolume>
<DSN>SYS.TEMP</DSN> <volume>Disk1</volume>
</defaultVolume>
<defaultVolume>
<DSN>NNNN.DISK</DSN> <volume>Disk1</volume>
</defaultVolume>
<defaultVolume>
<volume>Disk2</volume> <DSN>MMMM.DISK</DSN>
</defaultVolume>
</defaultVolumeMapping>
<units>
<unit
name="SYSDA"
isDefault="true">
<volumes>
<volume
name="DEFAULT"
path="C:\ProgramData\Raincode\Batch\DefaultVolume"
isDefault="true" />
<volume
name="Disk1"
path="C:\ProgramData\Raincode\Batch\Disk1"
isDefault="false" />
<volume
name="Disk2"
path="C:\ProgramData\Raincode\Batch\Disk2"
isDefault="false" />
</volumes>
</unit>
</units>
The example above explains the following:
-
If
DSNstarts withSYS.TEMPorNNNN.DISK, it will be physically stored on DISK1. The default path isC:\ProgramData\Raincode\Batch\Disk1. -
If
DSNstarts withMMMM.DISK, it will be physically stored on DISK2. The default Path isC:\ProgramData\Raincode\Batch\Disk2.
The DSN will be stored in the defaultVolume if none of the above DSN is specified.
<DSN> refers to the dataset name that must be stored on the specified volume. It contains a <DSN> element, a regular expression (regex) representing the DSN stored in this volume.
4.8. Environment variables for steps
The catalog configuration defines environment variable values that Submit will set at the beginning of each step such that the executing program can retrieve this information if needed. Below is an example.
<environmentVariables>
<envvar name="Name1" stepId="StepRegEx">Test1Value</envvar>
<envvar name="Test2" pgm="PRGB1">Test2Value</envvar>
<envvar name="Test3" pgm="PRGA.*">Test3PRGA</envvar>
<envvar name="Test3" >Test3OTHER</envvar>
</environmentVariables>
<environmentVariables> is a list of <envvar> elements. These have one mandatory attribute: Name, which is the name of the variable, and a set of optional attributes, as defined in the table below.
| Attribute name | Function | Typical Value |
|---|---|---|
jobID |
Regular expression to be matched on current JobID |
00X1.. |
jobName |
Regular expression to be matched on current Job Name |
TSK01.* |
pgm |
Regular expression to be matched on current PGM=clause |
PRG001 |
stepID |
Regular expression to be matched on the current StepID |
0001.* |
The value of the environment variable is the character data inside the <envvar> element.
| The name attribute is mandatory, and the other attributes are optional. |
The definition of environment variables and their values is conditional, based on regular expressions on Program Name, StepID, and JobID. If several regular expressions are defined for one <envvar> (e.g., stepId= "0001.*" and PGM="PRG01"), all of them must match to define the environment variable.
If no regular expression is given, the environment variable is always defined.
The list of <envvar> is evaluated in the order it appears in the .xml. If the same name attribute exists multiple times, only the first match is used.
|
4.9. JCL Automatic DD card definition
The mainframe can define a DD card for a step not explicitly declared in the JCL. The catalog supports this through the <autoDDCardDefinitions> section containing <ddCard> elements. An example is illustrated below.
<autoDDCardDefinitions>
<ddCard name="AUTO1" RECFM="FB" LRECL="120"/>
<ddCard name="AUTO2" />
</autoDDCardDefinitions>
The ddCard element defines a dataset in the SYSOUT directory. It has one mandatory attribute: Name, which is the DD card name, and a set of optional attributes, as defined in the table below.
Attribute name |
Function |
Typical Value |
jobID |
Regular expression to be matched on current JobID |
00X1.. |
jobName |
Regular expression to be matched on current Job Name |
TSK01.* |
pgm |
Regular expression to be matched on current PGM=clause |
PRG001 |
stepID |
Regular expression to be matched on the current StepID |
0001.* |
RECFM |
RECFM= format to use for the DD card (FB, VB …). Default is the format of |
FB |
LRECL |
LRECL= value to use for the DD card. Default is the value of `SYSOUT`120 |
If several regular expressions are defined for one <ddCard> (e.g., stepId= "0001.*",PGM="PRG01"), all of them must match to define the DD card.
If no regular expression is defined, the DD Card is always defined.
4.9.1. Example
If <ddCard name="AUTO1" RECFM="FB" LRECL="120"/> is defined and the JCL is:
//SIMPLE JOB CLASS=A,MSGCLASS=C
//STEP1 EXEC PGM=TST01
The JCL would be equivalent to the following:
//SIMPLE JOB CLASS=A,MSGCLASS=C
//STEP1 EXEC PGM=TST01
//AUTO1 DD RECFM=FB,LRECL=120,SYSOUT=*
This will create a file:
For JCL 4.1:
SYSOUT/JOB0000000001.SIMPLE/STEP1.AUTO1.meta
SYSOUT/JOB0000000001.SIMPLE/STEP1.AUTO1.txt
As of JCL 4.2:
SYSOUT/JOB0000000001-SIMPLE/STEP1/AUTO1.meta
SYSOUT/JOB0000000001-SIMPLE/STEP1/AUTO1.seq
4.10. JCL connection string retrieval
When a program using a DB is used, it requires a connection string and a DB Type to pass to rclrun. On the mainframe, this is typically defined by a configuration that associates a Job or Program Name to a Plan Name, while in IKJEFT01, PLAN (xxx) lets a user define the Plan name that will determine the connection to the DB. This section provides insights into how this is done in Raincode JCL.
4.10.1. Global DB connection definition
For development and debugging or demo purposes, the simple way to define the connection string is to use environment variables. Setting them defines a global connection string that will be used by Submit and rclrun.
Define:
RC_DB_TYPE = [SqlServer/DB2/Postgres] RC_DB_CONNECTION = <The connection string that will correspond to the DB engine defined by RC_DB_TYPE>
Example:
RC_DB_TYPE = SqlServer RC_DB_CONNECTION = "Data source=sqlsrv2017; Initial Catalog=PLICompilerTestDB; Uid=****; Pwd=*******"
When calling rclrun, IKJEFT01 will build the command line using the connection string:
RCLRUN.exe -SqlServer="Data Source= sqlsrv2017; Initial Catalog=PLICompilerTestDB; Uid=****; Pwd=*******"
| If PLAN is resolved, the new connection string will be used; otherwise, the environment variable will be used. |
4.10.2. Local DB connection definition
In contrast to a global connection definition, a local connection definition is more like the mainframe production environment.
Raincode JCL emulates the mainframe connection definition and PLAN by using two attributes of the catalog configuration: dbConnectionDataProvider and programDBConnectionDefinitions. These attributes are presented next.
Map a PLAN name to a connection string
The dbConnectionDataProvider attribute in the catalog configuration defines a mapping from PLAN names to connection strings. In this file, PLAN names are C# regular expressions linked to a connection string.
Lookup for this file is performed in the following order:
-
In the
catalogConfigurationelement of the catalog configuration, the value of the attributedbConnectionDataProvider, if it exists. -
An environment variable
RC_DB_FILEcontaining the path, if it exists. -
The default file name:
RcDbConnections.csv
The file uses a standard RFC 4180 comma-separated format without header, with one plan mapping per line with the following fields:
<PLAN regex pattern>,<DB Type>,<Connection String>
| If the connection string contains commas, it must be enclosed in double quotes to ensure proper CSV parsing. |
Lines beginning with # or // are considered comments and are ignored and can be used to annotate the file as needed.
|
Supported values for <DB Type> are: SqlServer,DB2 and Postgres.
Example entries are as follows:
PLANA01,SqlServer,"Data Source=sqlsrv2017; Initial Catalog=PlICompilerTestDB"
PLANB.*,SqlServer,"Data Source=sqlsrv2017; Initial Catalog=CPTTestDB"
The list of mappings is evaluated in the order the entries are written in the file. The first entry that matches the regular expression on the PLAN Name is used.
Before execution of any step after the change of the connection string by IKJEFT01, the environment variable is set to actual connection values:
RC_DB_TYPE=<DB Type> RC_DB_CONNECTION=<connection string>
Map a Job or program to a PLAN
The programDBConnectionDefinitions element in the catalog configuration contains a list of dbConnections elements. Each of these allows to define a mapping from jobId and/or ProgramId, and/or stepId using a C# regular expression to a PLAN Name. This is done through the definition of attributes on dbconnection, all of which are optional.
Attributes |
Description |
Type |
jobId |
Regular expression to be matched on current JobID |
Regular expression string |
jobName |
Regular expression to be matched on current Job Name |
Regular expression string |
pgm |
Regular expression to be matched on current PGM=clause |
Regular expression tring |
stepId |
Regular expression to be matched on the current StepID |
Regular expression String |
The value of the plan name is the character data inside the element.
The elements are evaluated in the order of their appearance in the configuration file, and the first match is used. If an entry does not specify a given attribute, matching will succeed for any value of that attribute.
An example list of definitions is as follows:
< programDBConnectionDefinitions >
<dbConnection pgm="PRGB1">PLANA01</dbConnection >
<dbConnection pgm="PRGA.*">PLANA02</dbConnection >
<dbConnection JobId=".*" >PLANOTHER</dbConnection >
</programDBConnectionDefinitions >
Since <dbConnection pgm="PRGB1">PLANA01</dbConnection> only specifies pgm, any jobId, any JobName, and any StepId are valid, i.e. all executions of PRGB1 will match the plan PLANA01.
| Another PLAN definition source is the IKJEFT01 PLAN (xxx) option. |
| The DB connection string lookup logic can also be customized programmatically, see custom plan mapping and Password plugin for more information. |
4.11. Sysout Folder Naming Convention
The unique job folder under the sysoutFolderPath can be configured by editing the sysoutFolderNamingPattern option in the catalog configuration. Two components have a specific meaning: ID and NAME. The ID string is replaced with the unique job ID, while the NAME string is replaced with the job name. The ID string is mandatory, whereas the NAME string is optional.
For Example:
sysoutFolderNamingPattern="JOB{ID}.{NAME}"
When the job name is not yet known, such as when a job is submitted, but there are errors in parsing, the job name is set to UNKNOWN. Once the job name is known, the sysout folder will be renamed accordingly.
This directory contains different files and directories:
-
JCLListing.JCL: The listing of JCL with all the included items resolved.
-
MSGLOG.txt: The messages displayed on the console.
-
PROCESS.txt: The list of processes executed by this job.
-
RETURNCODE.TXT: The return code of the job.
-
SYSLOG.<job name>.txt: The syslog of the job. Information about the job and its different steps.
-
SerializedJob.json: Raincode internal usage for restart.
For each PROC/STEP, there is a directory containing the files generated by the job, e.g. SYSOUT, SYSPRINT. These files are only present if they are not empty.
4.12. SDSN wait
Specifies the installation policy for batch jobs that must wait to enqueue the dataset (Locking). Possible values are NO, YES, 1-999999 with a default of 3600 seconds (one hour)
Specifies whether to cancel jobs that must wait to enqueue the dataset:
-
NO: The system cancels the job, releases resources, and issues the message RC904. -
YES: When YES is specified, and a batch job’s enqueue request cannot be satisfied, it will wait forever until it gets the resource -
1-999999: A timeout value in seconds to wait. If the enqueue request cannot be satisfied in the defined time, the system cancels the job and issues message RC904.
| Use caution when specifying YES or a timeout, as this can cause deadlocks with other jobs in the system. |
4.13. SMS Configuration
The Storage Management Subsystem (SMS) allows for the creation of templates with predefined data configurations by system programmers. Datasets can then be attached to such templates rather than repeating all the parameters file after file. SMS saves time and effort and, even more importantly, allows for a centralized and more abstract management of file properties.
Raincode’s JCL Emulator supports for SMS through two DD parameters, namely DATACLAS (Data Class) and STORCLAS (Storage Class). These parameters are specified in a configuration file. The default path of the configuration file is C:\ProgramData\Raincode\Batch\SMSConfig.txt.
A typical example of the contents of the configuration file:
DATACLAS:DSCLAS01=RECFM=FBA,LRECL=132,BLKSIZE=900
STORCLAS:SCLAS01=VOL=SER=VOL1
DATACLAS:DSCLAS02=DCB=(RECFM=FB,LRECL=120,BLKSIZE=2000)
STORCLAS:SCLAS02=VOL=SER=DEFAULT
The configuration file’s default location can be overidden using a smsConfigFilePath attribute in the Raincode.Catalog.xml.
For more details, please refer to the section Default catalog configuration. When Submit executes, it first checks for SMSConfig.txt at the location specified in the catalog. If it is not found, it checks at the default location to fetch the values for both classes.
4.14. Substvar
The JCL parser supports substituting variables that start with the # @ characters (e.g., # @VAR1). The values for these variables are stored in an XML file specified in the catalog configuration attribute substitutionVariableFilePath. The format of the file is given in the example below:
<Substvars>
<Variable Name="# @MYVAR" Value="VAL1"/>
<Variable Name="# @TEST" Value="HELLO"/>
</Substvars>
Variables can also be passed through the IJCLPreprocessor interface when the UpdateSubstvarVariables method is called. It is simply a dictionary of key/value pairs.
4.15. Setting up File Shares and UNC path locations
Setting up a file share and accessing it with its UNC path means having a centralized file share location, allowing a multi-batch server environment. Each batch server will access volumes and their datasets via the respective UNC path.
To enable this, first, share the folder on the server and note the remote path to the share. Then, modify the catalog configuration file to use the new share (for sysout, volumes, etc.) using the remote path.
4.16. Unit and Volume Configuration
Units are simply a named collection of volumes. The default unit is SYSDA.
Attribute |
Default Value |
Description |
name |
Name of the default unit |
|
isDefault |
FALSE |
The unit is the default unit |
Volumes map to drives or folders on disk. They can be UNC shares or local folders.
| In a distributed environment, the volumes should reside on a UNC share. |
Attribute |
Default Value |
Description |
name |
Name of the volume. |
|
path |
Folder that contains the data of the volume. It can be omitted if the catalogFormat is db and all the data are mapped to VSAMSql. |
|
isDefault |
FALSE |
Is it the default volume. |
To add new volumes to the catalog configuration, manually create a new folder on disk and add a new <Volume> element (under the <Volumes> element) with the path to the newly created folder.
4.17. Accessing catalog from a Linux Machine Using SMB
The Raincode catalog (Catalog.Configuration.xml) stored on a linux machine can be accessed remotely through two common file-sharing protocols:
-
NFS (Network File System)
-
SMB (Server Message Block)
This section focuses on guiding you through the process of accessing the Raincode catalog on a Linux machine using the SMB protocol.
By setting up an SMB file share, the Catalog.Configuration.xml file can be accessed and managed from a Windows environment, leveraging tools like Catalog Explorer and Record Editor without direct Linux support.
4.17.1. Creating and configuring SMB File share
In Azure:
-
Create a new Storage Account
-
Set up a File Share using the SMB protocol
-
Navigate to Storage Browser→ File shares
-
Click Add file share
-
Mount SMB File Share on Windows:
-
Right click on the file share and select Connect.
-
Under the Windows tab, choose a network drive letter (e.g.,
U:Drive) to mount the SMB share.
-
Copy the Azure connection script.
-
Run the script in PowerShell to mount the SMB share as a network drive.
-
The mounted network drive will now be visible in Windows File Explorer.
4.17.2. Mount SMB File Share on Linux
-
In Azure, select the Linux tab and copy the connection script.
-
Run the script on your Linux machine to mount the SMB share.
4.17.3. Integrating Linux Catalog with SMB Share
-
Place your
Raincode.catalog.xmlto the mounted SMB file share and ensure theDefaultVolumepath in the configuration points to the SMB file share for Windows accessibility.
-
Run the JCL using the
Submitcommand with the Catalog Configuration parameter to reference theRaincode.Catalog.xmlfrom the SMB share.
4.17.4. Accessing Linux Catalog on Windows
-
Open the mounted U: drive in the Windows File Explorer to view folders and files created after executing the JCL.
-
Launch Catalog Explorer on Windows and point it to the mounted SMB share (e.g., U:\raincode\Batch) using File→ Change Configuration.
-
You can access catalog content directly through the Catalog Explorer.
-
Double-clicking the file (e.g.,
SUBSTR.SORTED.FILE) will open it in the Record Editor for editing.
4.18. Use XML include in Raincode.Catalog.xml
Using <environmentVariables> or <programDBConnectionDefinitions> entities in the catalog configuration file may make this file large and unwieldy. So, store that information in separate files, possibly with different access permissions. This is possible since the catalog manager implements the W3C XML Inclusions (XInclude) 1.0 Recommendation for XML inclusion.
To allow this, the catalogConfiguration element needs to contain a xmlns:xi="http://www.w3.org/2003/XInclude" attribute. Inclusion of a file is then done by using an xi:include element, e.g. <xi:include href="file name" />.
xmlns:xi="http://www.w3.org/2003/XInclude" is a hardcoded signature that is recognized by the catalog manager. Even though it refers to a URL, your system does not need to be connected to the internet, there will be no connection to download anything. This signature is used simply to conform to the w3.org standard.
|
Sample usage of XML Include
File: Raincode.Catalog.xml
<catalogConfiguration
xmlns:xi="http://www.w3.org/2003/XInclude"
…
>
…
<xi:include href="./envvars.xml" />
</catalogConfiguration>
File: envvar.xml
<environmentVariables>
<envvar name="Test1" stepId="STEP1.*">Test1Value</envvar>
<envvar name="Test2" pgm="PRGB1">Test2Value</envvar>
<envvar name="Test3" pgm="PRGA.*">Test3PRGA</envvar>
<envvar name="Test3" >Test3OTHER</envvar>
</environmentVariables>
The file envvar.xml will be included, and the actual configuration used will be equivalent to the following:
<catalogConfiguration
xmlns:xi="http://www.w3.org/2003/XInclude"
…
>
…
<environmentVariables>
<envvar name="Test1" stepId="STEP1.*">Test1Value</envvar>
<envvar name="Test2" pgm="PRGB1">Test2Value</envvar>
<envvar name="Test3" pgm="PRGA.*">Test3PRGA</envvar>
<envvar name="Test3" >Test3OTHER</envvar>
</environmentVariables>
</catalogConfiguration>
4.19. Customizing Legacy Runner calls
The catalog configuration has two means to customize the calling of the legacy runner:
-
Instead of the default runner, a user-defined runner can be specified
-
Whenever a runner is called, additional arguments can be added to the list of arguments.
The former is done through the legacyRunner entity, e.g., as follows:
<legacyRunner>
<runner>/opt/bin/rcrunner1</runner>
</legacyRunner>
The latter is done through the legacyRunnerParameters entity, e.g., as follows:
<legacyRunnerParameters>
<param>-PluginPath=C:\plugins\</param>
<param>-Plugin=passwordRewriter.dll</param>
</legacyRunnerParameters>
Both of the above can be further fine-tuned. Following the same pattern as environment variable definitions, different runner and parameter values for specific steps or programs can be defined. For example, we can run a different runner on specific program calls or JCL steps, and enable Trace level logging whenever a certain program will be called:
<legacyRunner>
<runner prg="MYPROG" >/opt/bin/rcrunner1</runner>
<runner step="STEP001" >/opt/bin/rcrunner1</runner>
</legacyRunner>
<legacyRunnerParameters>
<param pgm="SPPROG">-LogLevel=Trace</param>
</legacyRunnerParameters>
5. Utilities
Raincode JCL provides several utility programs that emulate the functionality of their mainframe counterparts, such as the IDCAMS file manipulation utility. All these programs are located in the installation directory, where Submit.exe is also found and they have the same name as their mainframe counterpart to ensure seamless treatment of JCLs. This chapter presents the details of several utilities provided by Raincode JCL.
5.1. Implemented JCL Utilities
Utility name |
Aliases |
Description |
ScanOnly mode |
Run in-process |
Copies a dataset into file(s) |
Yes |
Yes |
||
CPY2PDS |
Copies a file into a PDS |
No |
Yes |
|
IMS Region controller - Provides access to the IMS BMP to the database |
Yes |
Yes |
||
DSNTEP2TSQL |
Executes dynamic SQL statements |
No |
Yes |
|
DSNTIADTSQL, DSNTIAUD, DSNTIAULDB2, DSNTIAULTSQL |
Unloads data from DB2 tables into sequential datasets |
No |
Yes |
|
DSNUTILBSQL, INZUTILB |
Handles DB2 commands from a JCL |
Yes |
Yes |
|
EZTPA00 |
Loads and executes an easyTrieve program |
Yes |
Yes |
|
Provides file and data processing capabilities |
Yes |
Yes |
||
Provides dataset backup and restore capabilities using ZIP archives |
Yes |
No |
||
ICETOOL |
Performs multiple operations on one or more datasets in a single step, using the capabilities of DFSORT |
Yes |
Yes |
|
Access Method Services Program that provides file manipulation, including creation, modification, and deletion of datasets |
Yes |
Yes |
||
Copies and merges partitioned datasets |
Yes |
Yes |
||
ICEGENER |
Copies sequential datasets or converts sequential datasets to PDS |
No |
Yes |
|
IEFBR14 |
Implements a no-op operation as a separate process |
No |
Yes |
|
IKJEFT01A, IKJEFT1A, IKJEFT1B |
Executes TSO commands in a batch job |
Yes |
Yes |
|
SUPERC |
Compares datasets and performs dataset searches |
Yes |
Yes |
|
FTP, SFTP |
Provides FTP (a mainframe-compatible FTP implementation) and SFTP (an implementation with similar syntax) |
No |
No |
|
SETLABEL |
Sets a label to a given dataset |
No |
Yes |
|
SORT |
ICEMAN |
DFSORT implementation |
Yes |
Yes |
File archiving and Email sending |
Yes |
No |
5.2. IDCAMS
IDCAMS (Integrated Data Cluster Access Method Services) is a file manipulation utility. It allows for the creation, modification, and deletion of datasets.
5.2.1. General Assumptions
Standard IDCAMS entry name specifications are used. Lowercase characters are converted to uppercase. Invalid characters outside of the 0-255 range are silently ignored.
Windows-reserved file names CON, PRN, AUX, NUL, COM[1-9], and LPT[1-9] cannot be used as a dataset name qualifier.
|
5.2.2. Additional command line arguments
The following command-line arguments have been added to the Raincode implementation:
-
ScanOnly: performs only scanning/parsing of passed input -
PreProcessDump: dumps preprocessed input to a file -
ScanToDb: works in pair withScanOnlyto dump information about the statements after parsing by creating a database table of statements, their parameters, and the indication of a successful parsing.
5.2.4. Supported functional commands
Commands are listed in the unabbreviated form. Standard IDCAMS abbreviations can be used.
Allocate datasets
ALLOCATE DATASET (dsname)
[FILE(ddname)]
[NEW|OLD|SHR|MOD]
[KEEP|CATALOG|DELETE|UNCATALOG]
[DIR(integer)]
Allocates dataset dsname.
DIR must be specified for a new partitioned dataset.
This command is only useful for allocating a new partitioned dataset.
Some of the parameters file(ddname), old, shr, mod, keep, delete, uncatalog are supported by the parser but are currently ignored.
|
Define alias
DEFINE ALIAS (NAME(aliasname) RELATE(entryname))
| At this time, the DEFINE ALIAS command is recognized but ignored. |
Define Cluster
Defines a VSAM cluster. Supported attributes are NAME, DATA, INDEX, RECORDSIZE, KEYS, ERASE/NOERASE, INDEX, CYLINDERS, KILOBYTES, MEGABYTES, RECORDS, TRACKS, ALTERNATEINDEX. Only KSDS indexed files are supported at the moment.
Implementation of the VSAM KSDS for DEFINE ALTERNATEINDEX has a few limitations, as mentioned below:
-
The definition
ALTERNATEINDEXmust be done before any actual creation of the datafile (open output and add record) -
The attributes used by
DEFINE ATLERNATEINDEXareKEYandUNIQUE/NOUNIQUE. All other attributes are ignored -
Added
ALTERNATEINDEXare alwaysUPDATE -
DELETEofALTERNATEINDEXis not supported -
BLDINDEXis not supported, asALTERNATEINDEXare always updated
Define GDG (Generation Data Group)
DEFINEGENERATIONDATAGROUP|GDG
(NAME(entryname)
[ LIMIT(limit)]
[SCRATCH | NOSCRATCH]
[EMPTY|NOEMPTY]
)
Define a GDG (Generation Data Group).
Delete datasets or GDG (Generation Data Group)
DELETE (entryname[ entryname …])
[ALIAS|
ALTERNATEINDEX|
CLUSTER|
GENERATIONDATAGROUP|
LIBRARYENTRY|
NONVSAM|
NVR|
PAGESPACE|
PATH|
TRUENAME|
USERCATALOG|
VOLUMEENTRY|
VVR]
[ERASE|NOERASE]
[FILE(ddname)]
[FORCE|NOFORCE]
[PURGE|NOPURGE]
[RECOVERY|NORECOVERY]
[SCRATCH|NOSCRATCH]
Deletes a dataset or a GDG.
Wildcards are supported in the entryname.
Partial datasets are deleted only if they contain no members.
Some of the parameters like alias, cluster, libraryentry, nvr, pagespace, path, truename, usercatalog, volumeentry, vvr, recovery, norecovery, scratch, noscratch are supported by parser but currently ignored.
|
List catalog entries
LISTCAT ENTRIES(entryname [ entryname...])|LEVEL(level)
[USERCATALOG]
[NONVSAM]
[OUTFILE(ddname)]
[NAME|HISTORY|VOLUME| ALLOCATION|ALL]
List catalog entries.
Listing non-VSAM datasets option is supported. Wildcards are supported in the entryname.
Listing to an output file is supported.
Some of the parameters usercatalog, history, volume, allocation, are supported by the parser but are currently ignored.
|
5.3. IEBGENER
IEBGENER is a copy utility that copies records from a sequential dataset or converts a dataset from a sequential organization to a partitioned organization.
There are four main use cases for IEBGENER:
-
Creating a copy without editing - creates an identical copy of the source dataset.
-
Creating a copy with editing - creates an edited copy of the source dataset by affecting the length, size, and organization of source records.
-
Creating a partitioned dataset or PDS member without editing - creates the partitioned dataset and/or creates PDS members identical to the source dataset.
-
Creating a partitioned dataset or PDS member with editing - creates the partitioned dataset and/or PDS members from the source dataset by affecting source records' length, size, and organization.
| The last use case, creating a partitioned dataset or PDS member with editing, is currently unsupported. |
5.3.1. General Assumptions
When creating a PDS member, the PDS directory needs to exist (see the chapter on mainframe file system emulation), or the DD=SYSUT2 data definition needs to contain information that the dataset is partitioned.
5.3.2. Utility control statements
There are five utility control statements: GENERATE, MEMBER, RECORD, EXITS and LABELS. Of these, EXITS and LABELS are not supported
GENERATE
The GENERATE statement is required when output needs to be partitioned, or editing is to be performed.
The GENERATE statement needs to be the first statement in the instream-data content.
|
[label] GENERATE [,MAXNAME=n]
[,MAXFLDS=n]
[,MAXGPS=n]
[,MAXLITS=n]
[,DBCS={YES|NO}]
All GENERATE statement parameters are supported by the parser; however, only MAXNAME and MAXFLDS parameters have their functionality implemented.
MEMBER
The MEMBER statement is used when the output dataset needs to be partitioned.
[label] MEMBER NAME=(name)
RECORD
The RECORD statement is used to define a record group and to supply editing information.
If the RECORD statement appears after the MEMBER statement, it defines editing information for that member, such as creating a PDS dataset (or PDS member) with editing.
If the RECORD statement appears just after the GENERATE statement, no MEMBER statements are allowed. When doing this, the RECORD statement defines editing information for the use case such as creating a copy with editing.
[label] RECORD [{IDENT|IDENTG}=(length,'name',input-location)]
[,FIELD=([length],
[{input-location|'literal'}],
[conversion],
[output-location])]
[,FIELD=...]
[,LABELS=n]
The parser supports all RECORD statement parameters. However, only the FIELD parameter has its functionality implemented, with the exception of its literal and conversion options.
| Record groups and labels are currently unsupported. |
5.4. Sort Runner
Raincode Sort Runner is designed for compatibility with the existing mainframe SORT utility; there is no change needed to the sort commands. It sorts, copies and merges datasets as it does on the mainframe.
The Sort Runner implements sort functionality for both SORT calls from COBOL or PL/I program and standalone SORT executions from a JCL. Its code resides in a .dll, which the Raincode runtime utilizes for all sort operations initiated from COBOL or PL/I. SORT.exe, also relies on this .dll to perform its work.
5.5. IKJEFT01
Raincode provides a bare-bone implementation of the IKJEFT01 utility. Only the following commands are partially implemented: RUN, OCOPY, and LISTCAT.
IKJEFT01 on the mainframe is often used to launch applications and connect them to the database. The Raincode implementation of IKJEFT01 relies on an underlying runner, which by default is rclrun.exe.
IKJEFT01.exe will invoke rclrun.exe and pass the required command-line arguments. To use an alternative implementation of a runner, configure it by adding an environment variable LegacyRunner and providing the full path to the executable of the alternative runner.
To provide connection strings to the utility, the user must provide an environment variable RC_DB_FILE containing the path to a file providing the connection strings. This file must be in the following format:
-
One connection string per line
-
Each line consists of three comma-separated parameters:
<System>, <DB Type>, <Connection String>
Supported values for DBType are SqlServer and DB2.
For more information on database connections and connection strings, refer to the section JCL connection string retrieval.
To debug a program launch by IKJEFTK01, add the parameter -DEBUG.
For example:
//STEP002 EXEC PGM=IKJEFT01,PARM='-DEBUG'
5.6. DSNUTILB
Raincode provides an implementation of the DSNUTILB load and unload functionality. It obtains the connection string from the environment variables RC_DB_CONNECTION and RC_DB_TYPE. Both are set up by the JCL interpreter when the DSN parameter is provided to the EXEC command. For more details on how to specify the database to be used, refer to the section JCL connection string retrieval.
By default, DSNUTILB executes the SQL queries without any modification. However, in some cases, for example, when the target DB type changes, it is desirable to rewrite the queries before executing them. For more details, refer to the Query rewriting section.
The utility understands UNLOAD commands of the following form:
UNLOAD TABLESPACE spacename FROM TABLE tablename LIMIT amount
WHEN condition
And LOAD statements of the form:
LOAD DATA RESUME YES INDDN name
INTO TABLE tablename WHEN condition (columndescription, *)
To load data, DSNUTILB uses either inserts or bulk inserts, depending on the UseBulk option. Bulk inserts are supported only for the SQL Server. The number of rows sent together to the database is defined by the LoadBufferSize option.
If the SYSDISK option is enabled and an error occurs during the insertion, the tool retries with a buffer 100 times smaller. This process continues until the specific row causing the issue is identified.
5.6.1. Command line options for DSNUTILB
The following are the command line options available for DSNUTILB
General
| Command-line option | Default value | Description |
|---|---|---|
|
Wait time (in seconds) before terminating the attempt to execute the command and generating an error. If not set use the C# default |
|
|
Path to the configuration file for the catalog. |
|
|
User define comment pass as argument |
|
|
Causes a JIT breakpoint to be hit. Useful for debugging custom hooks. |
|
|
Retain temporary files on disk instead of deleting them (default behavior) |
|
|
|
Command to use to clean-up the existing records during LOAD REPLACE, default is DELETE. Valid values are:
|
|
Registers a log file listener that outputs to the console |
|
|
The repository inventory file name to proceed |
|
|
Indication that input should only be parsed |
Load
| Command-line option | Description |
|---|---|
|
The size of the buffer used by the load. I.e. the number of lines inserted together. The default value is 500 for insert and 500000 for bulk insert (see UseBulk) |
|
Load uses bulk insert. Only supported by SQL Server. True by default for SQL Server |
Miscellaneous
| Command-line option | Default value | Description |
|---|---|---|
|
This command-line option is an additional .net 'app.config' file. |
|
|
Displays the tool’s help information. |
|
|
||
|
|
Displays a description of the program. |
|
|
Specifies the log level. Valid values are:
|
|
|
Displays the version information. |
5.7. DSNTIAUL
Raincode provides an implementation of the DSNTIAUL utility. It obtains the connection string from the environment variables RC_DB_CONNECTION and RC_DB_TYPE. Both are set up by the JCL interpreter when the DSN parameter is provided to the EXEC command. For more details on how to specify the database to be used, refer to the section JCL connection string retrieval.
By default, DSNTIAUL executes the SQL queries without any modification. However, in some cases, for example, when the target DB type changes, it is desirable to rewrite the queries before executing them. For more details, refer to the Query rewriting section.
5.8. DSNTEP2
Raincode provides an implementation of the DSNTEP2 utility. It obtains the connection string from the environment variables RC_DB_CONNECTION and RC_DB_TYPE. Both are set up by the JCL interpreter when the DSN parameter is provided to the EXEC command. For more details on how to specify the database to be used, refer to the section JCL connection string retrieval.
By default, DSNTEP2 executes the SQL queries without any modification. However, in some cases, for example, when the target DB type changes, it is desirable to rewrite the queries before executing them. For more details, refer to the Query rewriting section.
5.9. DFSRRC00
DFSRRC00 is the utility to access IMS through a JCL. Raincode only implements a subset of the original utility:
-
BMP/DLI: execute a program that uses IMS -
ULU: load/unload data
DFSRRC00 takes only one argument: the PARM taken from the JCL. Recall that on the mainframe this PARM consists of a comma-separated list of elements. The length of the list and the meaning of the elements depend on the value of the first element of the list.
Further, this document details what subset of DFSRRC00 is implemented.
5.9.1. BMP/DLI
If the first element of the parameter list is BMP or DLI, the program executes a batch program (COBOL or PL/I). The list of parameters is 21 elements long; but only a subset of these is supported, as outlined in the table below.
| List position | Name or value |
Description |
|---|---|---|
1 |
|
Execution mode |
2 |
MBR |
Specify the name of the program |
3 |
PSB |
Specify PSB name |
19 |
CKPTID |
Specify checkpoint for program restart |
20 |
IMSID |
Override IMS subsystem identifier |
21 |
DEBUG |
Set this parameter to TRUE to debug the IMSql plugin |
In Raincode IMSql, IMSID is the plan used to connect to the database. If the execution mode is BMP, IMSID is the region name, and the plan config_<IMSID> is used to get the connection string to the TM database.
5.9.2. ULU
If the first element of the parameter is ULU, the utility unloads or loads a DBD depending on the value of the second element: DFSURGU0 to unload or DFSURGL0 to load.
List Position |
|
Description |
1 |
|
|
2 |
|
Unload or load |
3 |
The DBD name |
The name of the DBD to unload/load is in the third position. When loading, the DFSUINPT DD is the dataset that will be loaded into the DBD. When unloading, the DFSURGU1 is the dataset in which the DBD will be unloaded. To get the connection to the database, the prefix (until the last .) of the IMS DSN is used as a key to search in the JCL connection string retrieval specification.
5.10. FTP
Raincode provides an implementation for the mainframe FTP functionality. It accepts both FTP and FTPS protocols. If FTPS is used, all certificates are accepted.
The connection information is read from the NETRC DD. The environment variable USERID contains the default user id that is used to find FTP.DATA
5.10.1. Implemented options and commands
The utility has support for two options: Exit and TRACe. The list of implemented commands is given in the table below.
Command |
Notes |
APpend |
|
AScii |
Uses the encoding defined in the |
BINary |
|
BLock |
|
CWd |
|
CD |
|
CDUp |
|
CLose |
|
DELEte |
|
DIr |
|
EBcdic |
Uses the encoding defined in the |
FIle |
|
Get |
Not for VSAMSql |
LCd |
|
LS |
|
MDelete |
|
MGet |
|
MKdir |
|
MOde |
Only |
MPut |
|
NOop |
|
Open |
|
PAss |
|
PUt |
|
PWd |
|
QUIt |
|
RECord |
|
REName |
|
RMdir |
|
STREam |
|
STRuctu |
Only |
TYpe |
Only |
User |
|
Verbos |
5.10.2. Command line options for FTP
Below are the details of the FTP command line options, as generated by ftp.exe.
General
| Command-line option | Description |
|---|---|
|
Path to the configuration file for the catalog. |
|
User define comment pass as argument |
|
Causes a JIT breakpoint to be hit. Useful for debugging custom hooks. |
|
Path to FTP.DATA config file. |
|
Retain temporary files on disk instead of deleting them (default behavior) |
|
Registers a log file listener that outputs to the console |
|
The repository inventory file name to proceed |
|
Indication that input should only be parsed |
|
Ftp timeout in second (default is 15). |
Miscellaneous
| Command-line option | Default value | Description |
|---|---|---|
|
This command-line option is an additional .net 'app.config' file. |
|
|
Displays the tool’s help information. |
|
|
||
|
|
Displays a description of the program. |
|
|
Specifies the log level. Valid values are:
|
|
|
Displays the version information. |
Plugin
| Command-line option | Description |
|---|---|
|
The list of plugins to be loaded when the tool executes. |
|
This command-line option specifies the path to plugins that are searched. |
Sftp
| Command-line option | Description |
|---|---|
|
hostkey for machine connecting to for Sftp. |
|
Path to Open SSH (PEM) certificate file for Sftp. |
|
Path to Open SSH (PEM) certificate file for Sftp. (alias of keyfile) |
|
PassKey for ppk certificate file for Sftp. |
|
Use Sftp. |
5.11. SFTP
Secure File Transfer Protocol (SFTP) replaces FTP, utilising Secure Shell (SSH) protocol version 2.0 to ensure safe file transfers. While it supports the same command structure as FTP, SFTP includes extensions that enable various types of authentication methods, as mentioned below:
Authentication Methods:
-
Username and Password
-
Users sign in with their usual username and password.
-
-
Public/Private Key (Certificate-based authentication)
-
This method requires OpenSSH keys:
-
The private key is stored on the FTP server
-
The public key is provided as a parameter to the SFTP command
-
-
-
Certificate plus a Passphrase
-
This method works like key-based authentication, but adds a Passphrase for more security.
-
Configuration Using DD Statements:
The authentication method is specified using specific DD names, as mentioned below:
-
ENVVAR DD
-
This dataset contains the values of two variables:
-
CLIENT (alias MFFTP_CLIENT): Specifies whether the client type is FTP or SFTP
-
SFTP_AUTH (alias MFFTP_SFTP_AUTH): Specifies which authentication method to be used
-
-
-
-
Contains the required authentication details
-
The parameters vary depending on the value of
SFTP_AUTH
-
-
SFTPPPK
-
The private key is used for authentication.
-
5.11.1. SFTPAUTH DD Statement - Format and supported commands
The SFTPAUTH DD statement provides optional input data used by Raincode FTP (RCFTP) for SFTP configuration and authentication.
It is read as a line-oriented text dataset and can include both FTP/SFTP parameter commands
and authentication entries in .netrc file format.
The file is interpreted based on the processing logic’s context.
Dataset definition
Below is an example JCL for a dataset definition.
//SFTPAUTH DD DSN=your.dataset.name,DISP=SHR
Supported dataset types are:
-
Sequential dataset
-
In-stream data
General Format Rules
-
One instruction per line
-
Empty lines are ignored
-
Lines may be truncated at column 72 when defined in-stream
-
Inline comments are supported using
;
Example for inline comments:
SFTP_AUTH 3 ; user/password authentication
In the above example, user/password authentication is treated as a comment.
SFTP Mode Activation
To enable SFTP mode, use one of the following:
CLIENT SFTP
or
MFFTP_CLIENT SFTP
Supported Parameter Commands
Each parameter follows one of these formats:
KEYWORD value
or
KEYWORD = value
Supported Keywords
The following keywords are supported:
-
PASVTYPE
-
INACTTIME
-
MFFTP_OUTPUT_LRECL
-
LRECL
-
RECFM
-
VOLUME
-
SBSENDEOL
-
SBDATACONN
-
CLIENTEXIT
-
MFFTP_CLIENT
-
CLIENT
-
SFTP_AUTH
-
MFFTP_SFTP_AUTH
SFTP Authentication Flags
The keyword: SFTP_AUTH <value> defines the authentication method.
SFTP_AUTH Values (Bitmask)
Value Meaning
-
1 = User ID
-
2 = Password
-
4 = Certificate / Private Key
-
8 = Passphrase
Common Combinations
Value Meaning
-
3 = User + Password
-
5 = User + Key
Value Meaning
-
12 = Certificate + Passphrase
-
13 = User + Key + Passphrase
If value is not specified then by default SFTP_AUTH will use 3 (User + Password)
|
Authentication Entries (.netrc - like format)
The dataset also supports authentication entries similar to .netrc.
Supported tokens
-
machine
-
login
-
user
-
password
-
pass
Examples
-
machine sftp.server.com login myuser password mypass
-
machine sftp.server.com user myuser pass mypass
Key-Based Authentication Entries
Additional tokens are supported for key-based authentication:
-
keypcn or keyfile - loads the private key from the specified path at runtime
-
keypass - provides the key Passphrase
-
hostkey - enables host verification
Example
-
keypcn: C:\keys\id_rsa
-
keypass: myPassphrase
-
hostkey: ssh-ed25519 AAAAB3…
Constraints
-
Only the OpenSSH private key format is supported
-
PuTTY .ppk format is not supported
-
Key file content is loaded at runtime.
Processing Behavior
The SFTPAUTH dataset is processed in two stages:
-
Parameter parsing (FTP/SFTP configuration)
-
Authentication extraction (
.netrcstyle parsing)
Examples
Example 1: Key-Based Authentication
//STEP6 EXEC PGM=FTP,
// PARM='FTP.MYORG.COM'
//ENVVAR DD *
CLIENT=sftp
SFTP_AUTH 13
/*
//SFTPAUTH DD *
machine ftp.myorg.com user ftptest
keypcn C:\keys\id_rsa
keypass mySecretPassphrase
/*
//INPUT DD *
Example 2: SFTP with a username and password
//STEP5 EXEC PGM=FTP,
// PARM='FTP.MYORG.COM'
//ENVVAR DD *
CLIENT=sftp
SFTP_AUTH=3
/*
//SFTPAUTH DD *
machine ftp.myorg.com user ftptest pass Xxxx
/*
//INPUT DD *
CD /home
PUT 'MY.DATA.PUBKEY'
QUIT
/*
Example 3: SFTP with a certificate and an OPEN command
//STEP6 EXEC PGM=FTP
//ENVVAR DD *
CLIENT=sftp
SFTP_AUTH=5
/*
//SFTPPPK DD DSN=PRIV.KEY,DISP=(SHR)
//INPUT DD *
OPEN ftptest@ftp.myorg.com
CD /home
TIMEOUT 20
PUT 'DATA.DATA1' SDATA1.txt
GET SDATA1.txt 'DATA.DATA2'
QUIT
/*
Example 4: SFTP with a certificate and SFTPAUTH and without an OPEN command
//STEP6 EXEC PGM=FTP,
// PARM='FTP.MYORG.COM'
//ENVVAR DD *
CLIENT=sftp
SFTP_AUTH=5
/*
//SFTPAUTH DD *
machine ftp.myorg.com user ftptest
/*
//SFTPPPK DD DSN=PRIV.KEY,DISP=(SHR)
//INPUT DD *
CD /home
TIMEOUT 20
PUT 'DATA.DATA1' SDATA1.txt
GET SDATA1.txt 'DATA.DATA2'
QUIT
/*
Example 5: SFTP with a certificate and .netrc and without an OPEN command
//STEP6 EXEC PGM=FTP,
// PARM='FTP.MYORG.COM'
//ENVVAR DD *
CLIENT=sftp
SFTP_AUTH=5
/*
//NETRC DD DSN=SFTPTEST.NETRC,DISP=OLD
//SFTPPPK DD DSN=PRIV.KEY,DISP=(SHR)
//INPUT DD *
CD /home
TIMEOUT 20
PUT 'DATA.DATA1' SDATA1.txt
GET SDATA1.txt 'DATA.DATA2'
QUIT
/*
With SFTPTEST.NETC containing:
machine ftp.myorg.com login ftptest
5.12. CompareFiles
Compares INFILE and OUTFILE DD. If the files are different, the return code is 16. Otherwise, it is 0.
PARM:
-
SKIP = n - skip the first n lines of INFILE
-
COUNT = n - compare only n lines
-
RECORD - if set, LSEQ files are compared as binary files; otherwise they are compared as a text file.
Example:
//PASO020 EXEC PGM=CompareFiles,PARM='SKIP=1'
//OUTFILE DD DSN=K14998.DATA.GROUP1,DISP=SHR
//INFILE DD DSN=K14998.DATA.RESULT,DISP=SHR
//*
5.13. File-AID
Raincode supports a subset of the batch capability included in BMC’s File-AID utility, which is widely used for file and data handling in mainframe systems. File-AID is offered as a program that can be executed by a job step in Batch. In that case, the SYSIN can contain multiple File-AID statements, which all consist of the following three things:
-
A DD name which refers to a dataset
-
The function to perform on the dataset
-
A list of optional parameters to manipulate records
Example:
//JOBNAME JOB JOB CARD INFORMATION
//STEP1 EXEC PGM=FILEAID,REGION=8M
//DD01 DD *
Andy van Steenderen 2004-03-25 306 Lazy Timber
German Brownlie 2001-08-25 596 Shady Pond
Angelo N.F.J. Fox 1991-11-01 918 Old Avenue
Hugh C.T. Clay 2003-04-19 891 Lazy Trafficway
Jolie W. Denhartog 2006-03-08 P.O. Box 17564
Garret Hartog 1969-12-07 125 Cinder Viaduct
/*
//DD01O DD DSN=MY.TEST.FILE,
// DISP=(NEW,CATLG,DELETE),RECFM=LSEQ,VOL=SER=DEFAULT,LRECL=80
//SYSIN DD *
$$DD01 COPY IF=(1,EQ,C'A,H')
/*
In the above example, DD01 is an instream dataset containing some dummy data. File-AID is used to copy records from DD01 to DD01O. The parameter IF limits the copied records to those that have the character A or H at the first position. Therefore, MY.TEST.FILE will contain the following:
Andy van Steenderen 2004-03-25 306 Lazy Timber
Angelo N.F.J. Fox 1991-11-01 918 Old Avenue
Hugh C.T. Clay 2003-04-19 891 Lazy Trafficway
5.13.1. Implemented functions and parameters
Raincode’s implementation of this utility can parse all valid File-AID programs but only implements a subset, detailed as the functions and parameters listed in the tables below. You can also check for the specific support of any File-AID command automatically by using the -ScanOnly flag together with the Submit command, which will trigger a check for validity (without actually executing the JCL). When this option is used, the RC_UTILITIES_PARSING_STATUS table in the repository will contain information about each statement in the program, and more specifically, an error message if a File-AID command requires functionality that is not yet supported by Raincode’s implementation.
Function |
Notes |
COPY |
|
DROP |
|
SPACE |
|
UPDATE |
|
USER |
Parameter |
Notes |
CEM |
|
EDIT |
|
EDITALL |
|
FORM |
Only supported for |
IF |
|
IN |
|
MAXENT |
|
MEMBER |
|
MEMBERS |
|
MOVE |
|
ORIF |
|
OUT |
|
PADCHAR |
|
REPL |
|
REPLALL |
|
RLM |
|
WRITE |
5.14. SMTPMAIL
The SMTPMAIL utility allows sending emails directly from JCL using an SMTP mail host. The utility accesses the following environment variables in order to establish a connection and send an email.
-
SMTP_HOST: Specifies the SMTP host.
-
SMTP_USER: Specifies the SMTP username.
-
SMTP_PASSWORD: Specifies the SMTP password.
-
SMTP_FROM: - If set to an email address, this variable defines the sender’s email address. If no email address is specified, the utility will default to sending the email from the host of the originator using the format
Jobname@localhost, whereJobnameis the name of the current JCL job being executed.
| The environment variables SMTP_USER and SMTP_PASSWORD are optional, depending on your SMTP server’s authentication requirements. |
Below is a sample code snippet.
The utility processes the SMTPIN DD in the following steps:
-
It identifies the recipient email addresses (xyz@raincode.com and abc@raincode.com).
-
After detecting a new line or an empty line, it identifies the email’s subject (e.g., SMTPMAIL Utility nightbuild test - Text and CSV file attachments).
-
If there is a space following the subject line, and the keyword MIME-VERSION appears immediately after, the JCL interprets this as an indication that one or more attachments are included and need to be processed. Once MIME-VERSION is identified, the JCL examines the next line to determine the type and source of the attachment. This line must specify:
-
The attachment type, such as TXT, CSV, or other supported formats (e.g., CONTENT-TYPE: TEXT/PLAIN or CONTENT-TYPE: TEXT/CSV).
-
A DDNAME, for example, ATTACH01 (e.g., CONTENT-DDNAME : ATTACH01, FILENAME=TEST.TXT). This declaration indicates that the content pointed to by the specified DDNAME will be treated as an attachment. The content will be processed in text format, resulting in an attachment named accordingly (e.g., TEST.TXT).
-
This utility also allows you to specify an attachment’s character encoding. For example: CONTENT-DDNAME: ATTACH01, FILENAME=TEST.CSV; ENCODING=1252 sets the CSV file’s encoding to 1252. You can specify the encoding using either its numeric code or its name, and this applies only to the attachment encoding received by the email’s recipient, with no change made to the encoding of the JCL file (SMTPTEST.CSV.FILE).
-
-
After another new line or an empty line, the body of the email is identified (e.g., Please find attached file.).
The CONTENT-DDNAME must appear immediately after the CONTENT-TYPE in the same sequence; if not, the utility will fail to recognize the attachment.
|
| Attachments are optional; if the attachment header metadata is not provided, the utility will still send the email containing only the subject and body. |
This utility also allows you to explicitly specify the sender by using a FROM: identifier. Recipient addresses must be specified separately, either through a TO: identifier or by listing the addresses on recipient lines as shown in the examples below.
| Only one FROM: identifier can be used. |
| Although using the FROM: identifier is recommended for clarity, the utility can also operate without it. |
You may also use aliases for both the sender and recipient addresses, as shown in the sample code. When aliases are included, the utility uses the text inside < > to determine the actual FROM and TO email addresses.
| Aliases must be applied to both the FROM and TO fields. |
5.15. SUPERC
Raincode provides a subset of the SUPERC utility, which compares datasets in the Mainframe systems similarly to diff programs. SUPERC is offered as a program that can be executed by a job step in Batch. In that case, the SYSIN can contain multiple SUPERC statements, which consist of the following four elements:
-
A list of parameters to manipulate and filter datasets before and during comparison. This list also contains the kind of comparison applied (by file, line, word or byte) and the format of the output;
-
A DD name which refers to a first and presumably older version of a dataset;
-
A DD name which refers to a second and presumably more recent version of a dataset;
-
A DD name which refers to the dataset containing the comparison output, as a listing.
Example:
//PSTEP001 EXEC PGM=ISRSUPC,
// PARM=(OVSUM,LINECMP,
// '',
// '')
//NEWDD DD DSN=FILE.INPUT1,DISP=SHR
//OLDDD DD DSN=FILE.INPUT2,DISP=SHR
//OUTDD DD DSN=FILE.OUTPUT,DISP=(,PASS),
// DCB=(LRECL=133,BLKSIZE=23408,RECFM=FBA)
In the above example, OLDDD is a dataset compared to another NEWDD dataset. SUPERC compares these two datasets according to
the options provided in the PARM field. When the LINECMP option is enabled, the datasets are compared line by line. In this example, OVSUM means that SUPERC will display comparison result in a summarised form (Overview summary) containing the types of differences (if any) between the datasets and their count. For instance, three matches and one insertion in the new dataset. This summary will be saved in FILE.OUTPUT.
If the OLDDD (FILE.INPUT2) file contains the following:
1000 Brussels 192088
1010 Admin City 7910
1020 Laeken 37936
and the NEWDD (FILE.INPUT1) file contains the following:
1000 Brussels 192088
1010 Admin City 7910
1020 Laeken 37936
1060 St-Gilles 51660
then, FILE.OUTPUT will contain the following:
1 ISRSUPC - FILE/LINE/WORD/BYTE/SFOR COMPARE UTILITY- 21/05/2025 10:55:23 PAGE 1
NEW: FILE.INPUT1 OLD: FILE.INPUT2
LINE COMPARE SUMMARY AND STATISTICS
3 NUMBER OF LINE MATCHES 0 TOTAL CHANGES(PAIRED+NONPAIR)
0 REFORMATTED LINES 0 PAIRED CHANGES(REFM + PAIRED)
1 NEW FILE LINE INSERTIONS 1 NON - PAIRED INSERTS
0 OLD FILE LINE DELETIONS 0 NON - PAIRED DELETES
4 NEW FILE LINES PROCESSED
3 OLD FILE LINES PROCESSED
5.15.1. Implemented functions and parameters
The product can parse SUPERC programs but only implements the parameters listed in the tables below. You can also check support for your program automatically by using the -ScanOnly flag with the Submit command. When this option is used, the RC_UTILITIES_PARSING_STATUS table will contain information about each option and process statement used in the SUPERC program.
Parameter |
Notes |
LINECMP |
May be an alias of |
DELTA |
May be an alias of |
OVSUM |
May be an alias of |
5.16. Query rewriting
DSNTIAUL, DSNUTILB, and DSNTEP2 can be extended with a plugin that rewrites the queries. For example, to rewrite Db2 queries to SQL Server queries.
A plugin that rewrites the queries (Db2 queries into SQL Server queries) is part of the distribution. This plugin uses cobrc for rewriting process and stores the results in a SQLite cache database.
To use this plugin, the utility must be called with two additional options -PluginPath=<QueryTranslation path> -Plugin=QueryTranslation
The plugin can be parametrized using different environment variables:
| Variable | Default value | Description |
|---|---|---|
RC_SQL_REWRITE_CACHE_DIR |
Temporary folder |
The folder where the cache DB will be stored |
RC_SQL_REWRITE_OPTION |
:SQLRuntimeRewriting :MaxMem=2G :ScriptPaths="%RCDIR%/Scripts" :RewriteSQLProc=CastSubstrings.Rewrite :SQLSemanticRulesFile="%RCDIR%/sql/SQLSemanticRules.xml" :SQLRewritingRulesFile="%RCDIR%/sql/DB2ToSQLServerRewritingRules.xml" :SQLRewritingRulesFile="%RCDIR%/sql/DB2ToSQLServerRewritingRules_TimeConversion.xml" :SQLSupportSelectStar :SQL=sqlserver :SQLServerConnectionString = "connection string to the DB" |
The options passed to |
RC_SQL_REWRITE_OPTION_APPEND |
The options that are appended to the default RC_SQL_REWRITE_OPTION |
|
RC_SQL_REWRITE_DONT_USE_CACHE |
FALSE |
If set to TRUE, don’t use the cache DB to store the translated queries. |
The SQLite cache database, named mssql-cache.sqlite, contains a single table cache with two columns: source and target. This database is in the directory %RC_SQL_REWRITE_CACHE_DIR%, if the database does not exist, the plugin creates it.
The %RC_SQL_REWRITE_CACHE_DIR% directory can also contain a second, optional, SQLite database named mapping-rewriting.sqlite. This database also contains a table named cache.
This can be useful if the translation process does not provide the expected result. For example, the target query needs to be optimized to achieve the expected performance.
The plugin searches for the query to be translated in the source column of mapping-rewriting.sqlite (if it exists). If the query is not found, it searches for it in mssql-cache.sqlite. If it is still not found, the plugin calls cobrc to translate the query and store the result into mssql-cache.sqlite.
| If needed, a custom version of this plugin can be created. Its sources are available inside the samples directory of the installation: %RCDIR%\plugins\Batch\QueryTranslation. |
5.17. IEBCOPY
The IEBCOPY JCL Utility allows for the copying and merging of Partitioned Datasets (PDS) and programs. This utility takes one or several datasets as input, and performs the action specified by the user, such as COPY or COPYGROUP (see the list of implemented options below). If no specific action is mentioned, and all the other prerequisites are met, a COPY action is performed by default.
Inputs and parameters
-
SYSUT1, if provided, this is the input dataset that will be copied or merged from. -
SYSUT2, if provided, this is the output dataset, which serves as the destination of the operation. -
Any additional named datasets may be used interchangeably as input or output, depending on the content of the
PARMfield orSYSIN. -
Both
PARMandSYSINcan contain control statements specifying the operation(s) IEBCOPY should perform, as well as the names of the input and output datasets to be used.
Example 1: Performing a simple COPY operation
//PSTEP00 EXEC PGM=IEBCOPY
//SYSUT1 DD DSN=MY.PDS1,DISP=SHR
//SYSUT2 DD DSN=MY.PDS2,DISP=SHR
//SYSIN DD *
COPY OUTDD = SYSUT2, INDD = SYSUT1
In this example, the PDS pointed to by SYSUT1 will be copied into the PDS pointed at by SYSUT2. This is specified in SYSIN. The COPY command takes two parameters: OUTDD, the output dataset, which is the destination of the copy operation, and INDD, the dataset to be copied.
In a COPY operation, only one output dataset should be provided in OUTDD, but a list of input datasets can be provided in INDD.
|
Example 2: Performing a partial COPY operation
//PSTEP00 EXEC PGM=IEBCOPY
//SYSUT1 DD DSN=MY.PDS1,DISP=SHR
//SYSUT2 DD DSN=MY.PDS2,DISP=SHR
//SYSIN DD *
COPY OUTDD = SYSUT2, INDD = SYSUT1
SELECT MEMBER = (MEMBER1, MEMBER4)
In this example, MY.PDS1 contains three named members: MEMBER1, MEMBER2 and MEMBER4. MY.PDS2 contains three named members as well: MEMBER3, MEMBER5 and MEMBER6. In the SYSIN statement, the user specifies that a COPY operation should be performed, from SYSUT1 to SYSUT2, but that only MEMBER1 and MEMBER4 from SYSUT1 should be copied. This means that at the end of the operation, the output SYSUT2 will contain five members: MEMBER1, MEMBER3, MEMBER4, MEMBER5 and MEMBER6.
If a PDS member has the same name in the input and the output, the PDS member is not copied. In such a case, the user must explicitly specify that the output PDS member should be replaced. To do so, the SELECT statement should be rewritten as follows: SELECT MEMBER = ((MEMBER1,, R), MEMBER4), R standing for REPLACE.
|
Example 3: A compact COPY operation
//PSTEP00 EXEC PGM=IEBCOPY
//SYSPRINT DD DSN=IEBCOPY.DATA.DATALOG,DISP=SHR
//SYSUT1 DD DSN=MY.PDS1,DISP=SHR
//SYSUT2 DD DSN=MY.PDS2,DISP=SHR
In this example, SYSIN and PARM are empty. However, since SYSUT1 and SYSUT2 are provided, a COPY operation will be performed using SYSUT1 as input and SYSUT2 as output.
5.17.1. Implemented commands and options
Command or option |
Notes |
COPY |
Can be abbreviated to |
SELECT MEMBER |
Can be abbreviated to |
5.18. BPXCOPY
BPXCOPY is a JCL Utility that allows copying datasets, initially from a Mainframe-based system to a UNIX-based system. Unlike IEBCOPY, the user may manipulate the ownership of the copied dataset, for instance, the group owner and the owner of the copied dataset. This utility takes one sequential dataset or one member of a partitioned dataset (PDS) and a destination path for the copy as input.
Inputs and parameters
-
SYSUT1, is the input dataset that will be copied. This parameter is mandatory. -
SYSUT2, is the destination path of the copied dataset. This parameter is mandatory. -
SYSTSPRT, a dataset containing the program’s output, which is usuallySYSOUT.
Unlike many other JCL Utilities, BPXCOPY exclusively relies on the PARM field for control options and statements. The options cannot be provided in SYSIN or in any additional dataset. The list of these options is available in the list of implemented options below.
Implemented options
Option |
Notes |
ELEMENT( |
The only mandatory option. It accepts one parameter |
GID( |
It accepts one parameter, |
UID( |
It accepts one parameter, |
LINK( |
Along with copying the dataset, several hard links to the copy may be created using this option. |
SYMLINK( |
Along with copying the dataset, several symbolic links to the copy may be created using this option. Requires |
SYMPATH( |
It represents the path of the symbolic links pointing to the copied dataset. Requires |
| According to the destination platform, several of these options may require elevated rights. The copy operation will fail if the user does not have the sufficient permissions to perform any of the operations requested by the program. |
Both UNIX and Windows systems are supported, so files can also be copied to a Windows based system. The SYSUT2 PATH is initially provided as a UNIX path, which may be of restricted access on a Windows system. To avoid this potential issue, the default root of the path in the destination file system is set to the path of the default volume of the catalog manager. This value can be modified using the command-line argument -WindowsRootPath=.
|
Example 1: Performing a minimal COPY operation
//PSTEP00 EXEC PGM=BPXCOPY, PARM=ELEMENT(MYCOPY)
//SYSUT1 DD DSN=MY.DATASET,DISP=SHR
//SYSUT2 DD PATH='u/output_directory'
//SYSTSPRT DD SYSOUT=*
In this example, the dataset pointed to by SYSUT1 will be copied to the destination path, which is
the concatenation of the value of SYSUT2 and the parameter of ELEMENT. It means that MY.DATASET will be copied to the folder u/output_directory/, under the name MYCOPY.
Example 2: Performing a COPY operation and create a symbolic link
//PSTEP00 EXEC PGM=BPXCOPY, PARM='ELEMENT(ACOPY) SYMPATH(".\bpxcpylink") SYMLINK("cpylink")'
//SYSUT1 DD DSN=MY.DATASET,DISP=SHR
//SYSUT2 DD PATH='u/output_directory'
//SYSTSPRT DD SYSOUT=*
In this example, the dataset pointed to by SYSUT1 will be copied to the destination path, which is
the concatenation of the value of SYSUT2 and the parameter of ELEMENT. It means that MY.DATASET will be copied to the folder u/output_directory/, under the name ACOPY. In addition, a symbolic link to this copy is created in the destination file system; its path is u/output_directory/bpxcpylink/cpylink. It means that the symbolic link called cpylink is pointing to the copied dataset located in u/output_directory/ACOPY. Creating a hard link also follows the same logic.
Example 3: Performing a COPY operation to a Windows destination system
//PSTEP00 EXEC PGM=BPXCOPY, PARM=ELEMENT(MYCOPY)
//SYSUT1 DD DSN=MY.DATASET,DISP=SHR
//SYSUT2 DD PATH='u/output_directory'
//SYSTSPRT DD SYSOUT=*
As in the other examples, the destination path is u/output_directory. If the destination system is Windows-based, it is possible to call this program using the -WindowsRootPath= flag to set the root folder. For instance, using the following command %RCBIN%/Submit.exe -File=BPXCOPYCOPERATION.jcl -WindowsRootPath="C:\myfolder" will copy MY.DATASET to C:\myfolder\u\output_directory.
5.19. FILEBKUP
The FILEBKUP utility provides dataset backup and restore capabilities using ZIP archives.
It works like mainframe JCL, making it easy to use in batch jobs.
5.19.1. Execution Modes
-
Backup Mode (default): Creates a ZIP archive of selected datasets.
-
Restore Mode: Restores datasets from a backup archive. Activated by passing the
-RESTOREflag, or calling PGM=FILERSTR.
Restore works directly from the contents of the backup archive: each dataset is matched and recreated from the metadata stored in the ZIP file. Because of this, the dataset (or its catalog entry) does not need to still exist for it to be restored — a dataset that was deleted, or an entire catalog that was lost, can be restored as long as a matching backup archive is available.
5.19.2. JCL Interface
FILEBKUP can be paramterized using 3 datasets as you can see in the following examples.
Briefly:
* SYSIN contains the list of datasets to include/exclude/rename
* BKUPDIR defines the backup directory (can also be set via environment variable)
* ARCHIVE defines the logical name of the backup (used as prefix for backup files and to locate archives during restore)
5.19.3. SYSIN Parameters
-
INCDSN(DSN pattern) or INCLUDE(DSN pattern): Includes datasets matching the specified pattern.
-
Supports wildcards:
(single qualifier) and*(multiple qualifiers). -
Pattern format is similar to
IDCAMS LISTCAT.
-
-
EXCDSN(DSN pattern) or EXCLUDE(DSN pattern): Excludes datasets from the included list.
-
Supports wildcards:
and*.
-
-
RENAME(from pattern,to pattern): Restore mode only. Renames a matched dataset while it is being restored.
-
Both the source and target pattern must end with a wildcard:
(captures exactly one qualifier) or*(captures the remaining zero or more qualifiers). -
Example:
RENAME(AC1.*,AC1.RST.)restoresAC1.DATA.MASTERasAC1.RST.DATA.MASTER. -
Example:
RENAME(AC2.DATA.,AC2.RST.)restoresAC2.DATA.PARAMasAC2.RST.PARAM. -
Several
RENAMEentries can be provided; the first pattern that matches a given dataset is applied. -
A dataset matched by
INCLUDE/EXCLUDEthat has no matchingRENAMEpattern is restored under its original name.
-
-
RETPD=n: Number of days to retain backup copies. Backups older than
ndays are automatically deleted when a new backup is created. Applies to backup mode only.
RETPD is ignored during restore.
|
INCLUDE/EXCLUDE wildcards are supported for both backup and restore.
|
5.19.4. ARCHIVE DD Statement
The ARCHIVE DD statement defines the logical name used for the backup file.
//ARCHIVE DD *
MY_BACKUP
/*
-
During Backup: the name is used as a prefix for the generated ZIP file:
<BACKUP_FOLDER>/MY_BACKUP_<timestamp>.zip -
During Restore: the name is used to find the most recent matching archive:
<BACKUP_FOLDER>/MY_BACKUP*.zip
To target a specific file, provide the full filename with the.zipextension.
5.19.5. Backup Directory
A backup directory must be specified using either:
-
The
BACKUP_DIRenvironment variable, or -
The
BKUPDIRDD statement (takes precedence over the environment variable).
Examples:
-
Windows:
C:\mybackup\ -
Linux:
/mnt/backup/raincode
5.19.6. JCL Examples
Backup
//BACKUP JOB
//*
//STEP1 EXEC PGM=FILEBKUP
//SYSIN DD *
INCLUDE(MY.**) -
EXCLUDE(MY.TEST.DATASET) -
RETPD=2
/*
//BKUPDIR DD *
d:/tmp/rcbackup
/*
//ARCHIVE DD *
MY.BACKUP
/*
Restore
The following restores datasets by matching them against the contents of the most recent
archive matching MY.BACKUP*.zip in d:/tmp/rcbackup. MY.** matches every dataset whose name
starts with MY., except MY.TEST.DATASET, which is excluded. Each restored dataset is renamed
under the MY.RESTORED. prefix, so MY.DATA is restored as MY.RESTORED.DATA.
//RESTORE JOB
//*
//STEP1 EXEC PGM=FILERSTR
//SYSIN DD *
INCLUDE(MY.**) -
EXCLUDE(MY.TEST.DATASET) -
RENAME(MY.**,MY.RESTORED.*)
/*
//BKUPDIR DD *
d:/tmp/rcbackup
/*
//ARCHIVE DD *
MY.BACKUP
/*
The RENAME clause is optional; a restore invocation with only INCLUDE/EXCLUDE clauses
restores matched datasets under their original names, for example:
//RESTORE JOB
//*
//STEP1 EXEC PGM=FILERSTR
//SYSIN DD *
INCLUDE(MY.**) -
EXCLUDE(MY.TEST.DATASET)
/*
//BKUPDIR DD *
d:/tmp/rcbackup
/*
//ARCHIVE DD *
MY.BACKUP
/*
5.19.7. Dataset Handling
Standard Datasets
Sequential, PDS, and GDG datasets are archived and restored directly, without conversion.
VSAM (KSDS) Datasets
VSAM datasets cannot be archived directly. Before adding one to the archive, the utility converts
its data to a sequential format using REPRO, staging it in a temporary dataset in the current job
step’s output area. This staging dataset is not cataloged and does not need to be cleaned up
manually. On restore, the sequential data is extracted to a similar temporary staging dataset and
loaded back into the VSAM dataset using REPRO.
This applies regardless of whether the catalog is stored on disk or in a database.
5.19.8. Retention Management
When RETPD=n is specified, old backups sharing the same name prefix are automatically
deleted at the start of each new backup run.
A backup is deleted if it is the N + 1 older copy.
5.19.9. Error Handling
The utility aborts with a user error (condition code 4095) if any of the following are missing or invalid:
-
No SYSIN input provided (neither via
SYSINDD nor-INPUT=argument). -
No backup name provided (neither via
ARCHIVEDD nor as a positional argument). -
No backup directory defined (
BACKUP_DIRenvironment variable orBKUPDIRDD). -
The specified backup archive is not found during restore.
-
A dataset listed in SYSIN is not found in the catalog (backup mode).
5.20. ZIP390
The ZIP390 utility aims to handle and exchange datasets. Specifically, the Raincode implementation enables dataset compression and supports sending emails with or without attachments.
ZIP390 takes its arguments from SYSIN. The user must first specify which ACTION they want to perform
(either ZIP for archiving a dataset, or EMAIL to send an email that may contain an attachment).
Then, depending on the intended action, several other fields may be required. For instance, if the user wants to
send an email, the fields HOST, FROM, and TO are required.
The four examples below illustrate the different use cases currently implemented in Raincode ZIP390
Example 1: Sending a simple email with one or several recipients
//STEP020 EXEC PGM=ZIP390
//SYSIN DD *
ACTION=EMAIL
HOST=EMAIL/localmail.example.com/25
FROM=from@example.com
TO=to1@example.com
TO=to2@example.com
TO=to3@example.com
SUBJECT=Test message - job ZIP390_email_only
BODY:
Hello,
This is an example of a simple email with no attachment.
Regards,
END:
/*
In this example, the user wants to send an email with no attachment. The fields HOST, FROM, and TO are required.
If SUBJECT is omitted, the email is sent with an empty subject. The body of the email is enclosed between BODY: and END:. However,
the body of the email may be omitted as well.
Each additional recipient requires an additional TO= field.
Example 2: Sending an email with one simple attachment
//STEP020 EXEC PGM=ZIP390
//COVERDD DD *
Please find attached the invoice for this billing period.
/*
//SYSIN DD *
ACTION=EMAIL
HOST=EMAIL/localmail.example.com/25
ATTACH=SEQ/COVERDD;COVER.TXT
FROM=from@example.com
TO=to@example.com
SUBJECT=Invoice 2026-0617-001
BODY:
Dear customer,
Please find attached your invoice.
Regards,
Billing department
END:
/*
To add an attachment to an email, add the ATTACH field. It should contain the name of the dataset to be attached.
The dataset name is prefixed by the type of the dataset. For now, Raincode supports SEQ (sequential dataset) and DSN (dataset).
It is possible to customize the name of the attached dataset. For instance, if the original dataset is named FOO.seq, the user can provide
an alternate name for the attachment by suffixing it to the ATTACH field after a semi-colon.
For instance ATTACH=SEQ/FOO.seq;FOOBAR.seq, where FOOBAR.seq will be the name of the attachment.
|
| It is possible to attach datasets present in the catalog, as well as inline datasets like in the JCL excerpt above. |
Example 3: Zipping a dataset
//STEP020 EXEC PGM=ZIP390
//LOGDD DD *
2026-06-17 01:00:00 INFO Batch run started
2026-06-17 01:00:05 INFO Batch run finished, rc=0
/*
//SYSIN DD *
ACTION=ZIP
IFILE=SEQ/LOGDD;RUNLOG.TXT
IFILE=DSN/ZIP390.TEST2.SUMMARY;SUMMARY.TXT
ARCHIVE=DSN/WEEKLY.ZIP
To compress a dataset, use the ACTION ZIP instead of EMAIL.
The dataset name to be archived should be provided in the IFILE field. Similar to Example 2, the dataset should be prefixed by its type (DSN or SEQ), and can be suffixed by an alternate name after a semi-colon. The name of the archive is provided in the ARCHIVE field.
Example 4: Sending an email with mixed attachments
//STEP030 EXEC PGM=ZIP390
//SEQDD1 DD *
Inline SEQ content #1, included in the zip as SEQDD1.
/*
//SEQDD2 DD *
Inline SEQ content #2, attached unzipped as plain text.
/*
//SYSIN DD *
ACTION=ZIP
IFILE=SEQ/SEQDD1
IFILE=DSN/ZIP390.TEST5.DATA1;DATA1.TXT
ARCHIVE=EMAIL/localmail.example.com/25/FULL.ZIP
ATTACH=SEQ/SEQDD2;EXTRA1.TXT
ATTACH=DSN/ZIP390.TEST5.DATA2;EXTRA2.TXT
FROM=from@example.com
TO=to1@example.com
TO=to2@example.com
SUBJECT=ZIP390 full scenario test
BODY:
Hello,
This message exercises every ZIP390 clause: IFILE (zipped),
ARCHIVE=EMAIL, ATTACH (unzipped) and multiple TO recipients.
Regards,
Batch platform
END:
/*
This use case covers a more complex scenario in which an email contains multiple attachments. Some of the attachments are archived, while others are left unchanged. This use case requires the ZIP ACTION keyword, even though an email is being sent.
In a first step, the datasets to be attached are processed: SEQDD1 and ZIP390.TEST5.DATA1 are zipped together in an archive named FULL.ZIP. Then, two other datasets are attached to the email: SEQDD2 and ZIP390.TEST5.DATA2. This means the email will contain three attachments: the ZIP archive and the last two datasets.
In this case, it is not necessary to explicitly provide the HOST field. It can be inlined in the ARCHIVE field, for example ARCHIVE=EMAIL/localmail.example.com/25/FULL.ZIP.
6. Catalog Explorer
The Catalog Explorer is a graphical user interface for accessing Raincode JCL catalog. The Catalog Explorer helps manage datasets of type File, PDS, and GDG.
This tool makes it easy to differentiate different datasets and see the metadata about the datasets without having to parse the XMLs manually.
For more details, refer to the Catalog Explorer Manual.
7. JCL Character Encoding
Character encoding (and decoding) refers to the process of transforming a set of characters to and from a sequence of bytes. The mainframe uses EBCDIC encoding, while most open systems, such as Windows or Linux, work using ASCII encoding. As a result, migrating from a mainframe requires addressing how character encoding will be handled.
For more information on character encoding and codepages in .Net, refer to the Microsoft documentation on the API for System.Text.Encoding.
|
In the remainder of this section, the following two codepages will be used as examples: number 500 is IBM EBCDIC (International), an EBCDIC code page with full Latin-1-charset support used in IBM mainframes, and number 1252 is the well-known Western European (Windows) codepage. Note that the former is not natively supported in .Net
7.1. Configuration settings and autodetection
There are two configuration settings in the Raincode Catalog that determine how character encoding is treated: defaultCodePage and codePages. The latter also determines autodetection of codepage behaviour, so it is covered here as well.
7.1.1. defaultCodePage attribute
The defaultCodePage attribute is mandatory; it defines the code page used by the system to store data files and source files.
-
Instream data found in JCLs are stored on disk using the encoding specified in the defaultCodePage
-
Unless overridden by a codePages element configuration, JCLs are read using the defaultCodePage
-
Submitassumes the encoding specified in defaultCodePage is used by the stack runtime -
All newly created datasets
[DISP=NEW]will use the defaultCodePage -
The
RC_CODEPAGEenvironment variable is set to this value before calling step programs. The effect of this is to enforce defaultCodePage as the default code page for any Raincode utility. -
The output files produced by utilities like
DSNTIAUL/DSNUTILBwill use defaultCodePage to encode data.
7.1.2. codePages element
The codePages element in the catalog configuration file contains two attributes, jclAlternate and jclRewrite, as described in the table next.
| Attribute | Type | Format |
|---|---|---|
jclAlternate |
String |
<Codepage identifier> |
jclRewrite |
String |
`"Alternate"' or `"Default"' |
jclRewrite is the codepage used to write JCL and PROCLIB on disk in the SYSOUT folder. If this is set to "Alternate" , the codepage specified in jclAlternate will be used. Otherwise, i.e. if undefined or "Default", the defaultCodePage will be used.
For example, if defaultCodePage="500", the value jclAlternate="1252" means the user expects JCL and PROCLIB to be written as ASCII on the disk when Submit reads the file.
jclAlternate is also the auto-encoding detection alternative codepage when reading a JCL or a PROCLIB, as discussed next.
7.1.3. Autodetection
In some situations, a user may need as many JCLs as possible to be in the ASCII encoding, yet some remain in EBCDIC for a specific reason (automatic conversion of the catalog, part of PROCLIB written by an application program, …). To allow this, Raincode provides Autodetection of Encoding of JCL and PROCLIB between the default encoding and the alternate encoding, both as specified above.
With jclAlternate set, when reading a JCL or a PROCLIB, SUBMIT will test for the “//” pattern as the beginning of the first line of the JCL. It will read the first two bytes of the file and use both encodings to determine which one translates those bytes to “//”. This encoding is then used to read the entire JCL.
7.2. JCL Character Encoding Strategies
There are three main strategies on how to treat character encoding:
7.2.1. Pure ASCII Encoding
When using purely ASCII, the JCL, PROCLIB and data files are encoded in an ASCII codepage. To do this, programs are compiled with StringRuntimeEncoding set to ASCII and the defaultCodePage in the Raincode catalog is ASCII , e.g. 1252.
The ASCII code page is the default for Raincode tools as it is the native encoding to Windows and Linux servers.
|
Advantages:
-
All third-party tools use the same
ASCIIencoding; it is more natural for an open system.
Disadvantages:
-
Files must be converted when transferred (from and to the Mainframe).
-
The collating sequence is different to
EBCDIC, and so the result of the sort may be different. -
When validating the migration, comparing the result file is more complicated due to the difference in encoding and collating sequence.
7.2.2. Pure EBCDIC Encoding
When using purely EBCDIC, i.e. the native encoding of the mainframe, the JCL, PROCLIB and data files remain encoded in an EBCDIC codepage. Programs are compiled with StringRuntimeEncoding set to EBCDIC, and the defaultCodePage in the Raincode Catalog is EBCDIC , e.g. 500.
Advantages:
-
Files do not need to be converted.
-
The collating sequence is identical as on the mainframe.
-
Validation of the migration by comparing the result file is more effortless.
Disadvantages:
-
Third-party tools need to be able to use
EBCDIC, which complicates data manipulation. -
Source editing requires a text editor that supports the
EBCDICcodepage.
7.2.3. Mixed Encoding
In a mixed encoding, data files are stored in EBCDIC and JCL and PROCLIB files are stored in ASCII or EBCDIC.
Programs are compiled with StringRuntimeEncoding set to EBCDIC, and the defaultCodePage in the Raincode Catalog is EBCDIC , e.g. 500. In addition, the codePages jclAlternate needs to be set to ASCII, e.g. jclAlternate="1252" (see the section on Autodetection for more information on the effect of jclAlternate).
This setting fundamentally allows data to be processed and stored in EBCDIC while sources are stored and edited in ASCII for convenience. In addition, the autodetection process allows JCL and PROCLIB files to be also stored in EBCDIC, permitting JCL and PROGLIB files to be generated by a program (which produces its data in EBCDIC format).
The stack compiler has options (for more details, refer to Encoding) to define the Encoding of runtime and sources.
Advantages:
-
Data files do not need to be converted.
-
The collating sequence is identical as on the mainframe.
-
Validation of the migration by comparing the result file is more effortless.
-
Editing of JCL may be done with standard third-party tools.
Disadvantages:
-
Third-party tools need to be able to use
EBCDIC, which complicates data manipulation. -
To be editable in standard third-party tools, JCL files need to be converted to
ASCII.
7.3. DD CARD Codepage Enforcing
For some operations, you may need to be able to enforce the encoding format, overriding the default format. This as some third-party utilities may require JCL instream data to be encoded in a specific codepage, or the encoding of the output file of the DSNTIAUL and DSNUTILB utilities may need to in a specific codepage.
Raincode JCL provides two extensions to the JCL DD statement: CODEPAGE=<integer value> and AUTOENCODE=<YES/NO>. The CODEPAGE setting overrides the default codepage that is specified in the catalog configuration file. AUTOENCODE=YES will allow the runtime to transparently convert the content of the file to the actual encoding that is being used by the runtime, if needed.
For example, in the JCL below the CODEPAGE=1252 is used to enforce the encoding of the instream commands on disk to be 1252. This allows third-party tools to easily work with the files. If the runtime uses EBCDIC (e.g. when using Pure EBCDIC Encoding or Mixed Encoding) then AUTOENCODE=YES ensures that it will transform the contents of the file to EBCDIC encoding before passing it to the program MYPROG.
//STEPXXX EXEC PRG=MYPROG
//INFILE DD CODEPAGE=1252,AUTOENCODE=YES,*
Instream command 1
Instream command 2
...
/*
Similarly, the CODEPAGE argument in the DD statement of the output file for the programs DSNUTILB and DSNTIAUL will modify the encoding of the output file to the specified codepage.
| Auto encoding supposes that the file is a pure text file and will blindly transform its contents. Consequently, if the file contains binary data, then this data will also be remapped, which will corrupt the file. |
8. VSAMSql
8.1. Introduction
The idea behind VSAMSql is to store the dataset data and meta information (i.e. the properties of a dataset, see also Mainframe file system emulation) in a database instead of on a file system.
All the Raincode tools and compiled programs use the file driver to access the files (i.e. datasets). To store the data in a database instead of on disk, the VSAMSql file driver is provided that redirects input-output instructions to the database. Consequently, all the programs that use the file driver interface can store data in the database seamlessly, as illustrated in the figure above.
The VSAMSql driver is designed such that one table can contain the data of multiple files, as long as each of them has the same properties, i.e. record length, key position, record type and record structure.
8.2. Catalog configuration
The Raincode catalog is configured to use VSAMSql for specific datasets through the datasetSqlMapping element of the catalog configuration file. For more details, refer to the Catalog configuration section.
The datasetSqlMapping element holds datasetTemplate child elements that map the files to the corresponding table in which the data must be stored, as described in Dataset mapping with tables. For each table, a datasetTemplate element declares the name of the table and the plan to use to connect to the database. One or more pattern elements use regular expressions to identify the files (Unit and DSN) mapped to the table. The parameters element describes the record: its length and keys.
Additionally, the catalog configuration file contains information about where the catalog should be stored (on the file system or in a database) and whether the file should be stored in the database or the file system. The attribute catalogFormat describes the location of the catalog: disk – the catalog is stored on the file system; db – the catalog is stored in the database; if the catalogFormat is db, catalogDbConnection is the plan/connection string. For more details, refer to map plan name to actual connection string to connect to the database. If the catalog is stored in the database, two tables are used to store the catalog information: CATALOG_META and CATALOG_LOCK.
8.3. Database model
8.3.1. Tables
The table VSAM_META contains meta-information about the files stored in the database:
-
ID: an SQL Server identity column -
FILE_NAME: the name of the file -
TABLE_NAME: the name of the table in which the data of this file are stored -
PARTITION: the partition number (see Partitions)
A table can store data from multiple files, provided that all the files have the same structure, including the same record length, keys, and record structure. Each data table contains the following columns:
-
RID: an SQL Server identity column -
FILE: the foreign key to theVSAM_META.IDcolumn -
PARTITION: the partition number (see Partitions) -
Data: the actual data as a binary array (VARBINARY) -
KEY: this column is only present for the VSAM file. It contains the key of the record. It is a computed-persistent column that is a substring of the Data column. -
KEY_[1…n]: there is one column for each alternate key of the VSAM file. It is a computed-persistent column that is a substring of the Data column.
If the catalog is stored in the database, two additional tables are created: CATALOG_META and CATALOG_LOCK.
CATALOG_META contains information about the catalog. There is one line representing each file.
CATALOG_LOCK is used to manage the locking of the files.
8.3.2. Partitions
When a file needs to be deleted, all its records must be deleted from the table. Deleting many rows (records) from a table with a DELETE statement is inefficient because lines are deleted individually. If the table contains only one file, the statement TRUNCATE can be used more efficiently.
If the table is partitioned, TRUNCATE can be used to delete all the data of one partition. So, if a table contains more than one file, one partition can be used for each file. Similarly, when a file needs to be deleted, TRUNCATE can be used to delete all the data of the corresponding partition.
During the generation of the creation script, the partitions element of the catalog configuration is used to know which partition need to be created. If a file isn’t associated with a partition, its data will be stored in the default partition (partition 0).
8.3.3. Stored procedures
One stored procedure is associated with each data table: DELETE_<table name>. This stored procedure is used to delete all the data of a file. It decides if DELETE or TRUNCATE should be used, depending on how many files are stored in the partition.
Some stored procedures are used to manage the catalog: WRITE_CATALOG, KEEPLOCK_CATALOG, LOCK_CATALOG, UNLOCK_CATALOG.
8.3.4. Database creation
The creation script of the database is generated by VsamSql.DbGenerator. This program reads the catalog configuration file, whose path is given as an argument, and generates a SQL file that contains the tables creation SQL script. This SQL script then needs to be executed on the database server.
VsamSql.DbGenerator can take a connection string to the database as an argument (-SqlDatabase), then it generates only the missing tables and updates the partition function.
An example table script generation is as follows:
VsamSql.DbGenerator.exe -CatalogConfiguration="C:\ProgramData\Raincode\Batch\Raincode.Catalog.xml" -OutputFile="output.sql"
For more details on VsamSql.DbGenerator arguments refer to command line options.
8.4. View creation
The Data column is binary data: the array of bytes corresponding to the COBOL or PL/I program record. In those programming languages the records are read as one array of bytes and are transparently mapped to a variable. This variable is usually defined in a copybook or include, and is composed by a hierarchy of sub-variables meaningful to the application. The application then accesses the sub-variables directly instead of working with the array of bytes that is the record.
To aid in developing programs that use VSAMSql that aren’t written in COBOL or PL/I, VSAMSql allows for the definition of views. The idea here is that these views decompose the Data column based on the variables defined in a COBOL or PL/I program, as shown in the following figure.
Triggers are associated with the view, enabling them to be used to both query and update the data.
The view can be created as below:
-
Use the COBOL or PL/I compiler to extract variable declarations from the program source code into an xml file:
cobrc.exe :DeclDescriptors= "output_xml_file.xml" :MaxMem=1G "cobol_program_or_copybook" :SQL=SqlServer
-
Use CopybookViewGenerator to generate the view and trigger the creation script from this xml file:
CopybookViewGenerator.exe -xml="output_xml_file.xml" -struct=NAME_OF_COBOL_VAR -table=TABLE_NAME -output="OUTPUT_FILE.sql" -conn="connection string to the DB"
-
Before executing the SQL script created from the above step, ensure the following SQL scripts are executed:
EbcdicFuncs.sqlandFunctions.sql(these are part of the compiler installation and can be found in"%RCDIR%\sql\CopybookViewGenerator").
8.5. Granting Permissions to Database Users
Specific access permission must be granted to allow a database user to interact with tables, stored procedures and functions within the VSAMSql environment.
-
Reader Access allows a database user to retrieve and view data from tables within the specified VSAMSql environment.
-
Writer Access allows a database user to insert, update or delete data from tables within the specified VSAMSql environment.
-
Execute Access grants a database user the right to execute the stored procedures and functions within the specified VSAMSql environment.
For more details on the generated stored procedures and functions, refer to the following files:
-
output.sql: created during database creation.
-
OUTPUT_FILE.sql: created during view creation using CopybookViewGenerator.
-
Ebcdic.sql and Functions.sql: included in the compiler installation and located in
"%RCBIN%\sql". They provide additional stored procedures and functions to support VSAMSql environment.
8.6. Load data
Data must be loaded into the tables while creating the catalog and database objects (such as tables, indexes, and views).
There are two ways to load data:
-
Using JCL: Copy the data from a disk file into VSAMSql.
-
Using the SQL Server bcp utility:bcp requires a more complex setup and is more efficient for handling large volumes of data.
8.6.1. Loading data using a JCL
Loading data using a JCL is the same as migrating a dataset, as described in Dataset Migration, because JCL sees the VSAMSql file as a dataset.
8.6.2. Loading data using bcp
The VsamSql.load utility does not directly load the data. Instead, it prepares the data to be loaded by the high-performance SQL Server bcp utility, specially designed for bulk data insertion into the SQL Server. This process involves transforming the input file into a format compatible with bcp. It generates a format file (.fmt) that specifies the format argument used by the bcp to import the data.
Once the data has been processed and all the output files are created, they must be loaded into the target SQL Server database using bcp.
For the demonstration on how to load the data using VsamSql.load and bcp refer to an example script, VsamSql.LoadData.ps1 located at "%RCDIR%\scripts\VsamSql".
You can also refer to the VsamSql.Load Command Line Options for details on how to use this tool.
8.7. Caches for read, write and update
In VSAMSql, multiple caches are implemented, each targeting a different kind of file use:
-
A prefetch or read-ahead cache for sequential read file access. It is fully flushed when a
START,READ KEY, (re)write, delete, or a change in the read direction occurs. -
An update cache for read and update operations in random file access, if the file is indexed by one unique key. It is partially flushed when it is full, and more space is needed, and fully flushed when the maximum number of writes or updates per commit is reached.
-
A write cache for inserting new records, either in sequential or random file access. It is fully flushed when it becomes full, when the maximum number of writes or updates per commit is reached, or when a
READorSTARTis performed.
It goes without saying that all caches are flushed (in their respective ways) when closing the file. The size of caches, as well as the number of writes for automatic commit, can be defined per file or per job, as described below. A cache size of 0 effectively disables that cache.
The caches require that in the VSAMSql connection string, the setting MultipleActiveResultSets=True is set.
|
8.7.1. Prefetch and Write cache considerations
The prefetch or read-ahead cache for sequential file read access enhances performance by retrieving records in advance and in bulk. The cache size is dynamic: at the first read, it is filled by fetching 10 records from the database. If a cache miss occurs, i.e., all 10 have been read, the cache is cleared, the size is multiplied by 10 and it is filled again by querying the database (for 100 records). Each such cache miss causes the cache size to be multiplied by 10, up to the prefetch limit defined in the cache configuration. A START, READ KEY, (re)write, delete, or a change in the read direction clears the cache and sets its size to 10 records. Also, a START does not fill the prefetch cache, only 1 record is read.
The write cache is typically useful when a significant amount of records are added to a sequential file. The write cache will store records into the cache and send writes to the database in a bulk write operation. To use this cache, all keys should be unique.
| Use the write cache only when you are certain that all keys are unique. Primary key uniqueness is validated only during the bulk write operation, not at the time the record is written by the program. Consequently, any program logic for handling duplicate keys will be ineffective, and the program will fail at cache flush time rather than at record write time. |
8.7.2. In detail: the workings of the update cache
The update cache stores both read and update operations, though it does not cache the insertions of new records.
The cache works as follows:
-
A read of a record causes it to be cached, and subsequent reads or writes of that record occur on the cache until that record is evicted, i.e. written to the database (if updated) and removed from the cache.
-
When a commit occurs, either due to the
commitRatebeing reached or the file being closed, all updates are evicted before the commit. -
Alternatively, when the cache is full, some of the oldest updated records will be evicted to make space for new reads (but no commit occurs unless
commitRateis reached). -
The cache is conservative: any operation that cannot be performed safely when operated on the cache will cause a complete cache eviction, followed by the operation performed directly on the database. For instance, a record update that changes the value of a unique key cannot be performed on the cache, but on an up-to-date version of the database, which must then be able to reject the update if it violates a unique key constraint. This rejection must happen immediately, and cannot be deferred to a future eviction of the cache.
-
The cache is also transparent: it does not require any changes to the application program that can thus read and write records without caring which of these operations will be optimized by the cache. Strict functional equivalence is guaranteed in all cases.
VSAMSql performance for reads and updates is then improved by a combination of two factors:
-
Re-reading a cached record replaces a costly database operation with an efficient in-memory counterpart.
-
When the records in the caches are evicted to the database, the updates are performed in bulk, instead of one by one if there were no cache.
8.7.3. Configuring the caches: lookup order
The size of caches, as well as the number of writes required for automatic commit, can be defined in many different ways. The driver takes the following steps to determine which values to use for cache sizes:
-
If there is a
SUBSYS=(VSQL, …)statement in the DD statement of the JCL (see Configuration in the JCL), that value is used. -
If there are cache values declared in the
.metaof the file, these are used. These are placed there at file creation time when there are entitites in aDriverParameterelement of the dataset template that is not specific to a job, step or program. This is described in Unrestricted parameters. -
If the dataset template for the file contains job- or step- specific
DriverParameterentities that apply, any entities giving cache values are used, as described in Job, Step or Program Specific parameters. -
If no values have been encountered, the default values for the driver, as described in Defaults are used.
8.7.4. Configuration in the Driver Settings
The size of caches can also be configured without editing JCLs. To achieve this, there are multiple ways in which changes can be made to the dataset template for the file, in the <datasetTemplate> XML element of the file.
The most straightforward way to do this, is to add attributes to the XML element, and the available attributes are as follows:
-
prefetch: Specifies the maximum size of the prefetch cache, in records, for sequential reads from VSAM. Prefetching enhances performance by retrieving records in advance and in bulk, thereby reducing the number of SQL queries and minimising network latency. -
updateCache: Specifies the size of the update cache, in records. It stores read records as well as record updates. Re-reading cached records avoids database accesses. Updated records (rewrites) are stored in this cache and then sent to the database as a bulk operation. This reduces the network latency by minimizing the number of database update calls. -
writeCache: Specifies the size of the write cache, in records, for insert operations. This is typically useful when a significant amount of records are added to a sequential file. The write cache will store records into the cache and send writes to the database in a bulk write operation. -
commitRate: Specifies the number of write/update operations that cause an automaticCOMMITto the database. Set to -1 to disable intermediate commits and commit only at the end of the program.
| As mentioned previously, a cache size of 0 effectively disables that cache. |
8.7.5. Job, Step or Program Specific parameters
As detailed earlier, in how to enable VSAMSql, in the <driverParameter> tag, attributes can be added that make these parameters be specific to a job, a step or a program. This effectively allows for cache values to be set for specific scenarios, without needing to edit JCLs.
If the job, step or program creates a VSAM file, the cache parameters are added to the .meta of that file. Alternatively, if the job, step or program reads or writes a VSAM file, the cache parameters are used for these accesses.
Inside the <driverParameter> entity, entities can be added that specify the values for the different caches (see above for a fuller description):
-
<prefetch>: Specifies the maximum size of the read ahead cache. -
<updateCacheSize>: Specifies the size of the update cache. -
<writeCache>: Specifies the size of the write cache. -
<commitRate>: Specifies the number of write/update operations that cause an automatic COMMIT to happen.
8.7.6. Unrestricted parameters
If the <driverParameter> tag has none of the attributes that restrict to job, step or program, these configuration parameters take effect at file creation time (since they are placed in the .meta file).
| If these values are changed in the catalog after a file has been created, these changes will not take effect on that file. |
For example, suppose we have the following cache configuration, for the VsamLite driver (with nonsensical values):
<datasetSqlMapping>
<datasetTemplate driver="VsamLite">
<pattern>
[...]
</pattern>
<driverParameter>
<prefetch>www</prefetch>
<updateCacheSize>xxx</updateCacheSize>
<writeCache>yyy</writeCache>
<commitRate>zzz</commitRate>
</driverParameter>
</datasetTemplate>
</datasetSqlMapping>
Whenever a file gets created, the cache settings are placed in the <FileConfig> element in the .meta as follows:
<FileConfig>
<DriverAssembly>VsamLite</DriverAssembly>
<DriverParameters>
<prefetch>www</prefetch>
<updateCacheSize>xxx</updateCacheSize>
<writeCache>yyy</writeCache>
<commitRate>zzz</commitRate>
</DriverParameters>
</FileConfig>
Do note the difference in the <DriverParameters> tag: plural versus singular.
While it is possible to manually edit these values in the .meta of a file, we urge caution. There is no error-checking on these values when the .meta file is read, and incorrect tags or values will lead to unexpected behavior.
|
8.7.7. Configuration in the JCL
In some cases, caching needs to be fine-tuned for a specific job step, and this can be done in the JCL itself. This configuration overrides all other configurations, allowing for fine-grained tuning.
For each DD statement that references a VSAMSql dataset, you can define caching parameters that apply only to that step by using:
SUBSYS=(VSQL,...)
The keywords for the different values are as follows (see above for their meaning):
-
READ or PREFETCH: The maximum size of the prefetch cache, in records.
-
WRITE or WRITECACHE: The size of the write cache, in records.
-
UPDATE or UPDATECACHE: The size of the update cache, in records.
-
COMMIT or COMMITRATE: The commit rate.
For example, when unloading a VSAM to a flat file, a large PREFETCH cache is useful.
//STEPULD EXEC=IDCAMS
//FILEIN DD DSN=...,
// SUBSYS=(VSQL,’PREFETCH=5000’)
//FILEOUT DD DSN=...
//SYSIN *
REPRO FILEIN(FILEIN) TO FILEOUT(FILEOUT)
/*
VSAMLite Driver Options
The following settings apply specifically to the VSAMLite driver (VSAMSql using SQLite as the backend).
Exclusive Mode
SUBSYS=(VSQL,'EXCLUSIVE')
This option opens the file in exclusive mode, restricting access to a single process.
Benefits:
-
Ensures exclusive access to the file
-
Prevents concurrent reads or writes by other processes
-
Significantly improves performance.
Limitations:
-
The file cannot be accessed by any other process while in use.
No Journal Mode
SUBSYS=(VSQL,'NOJOURNAL')
This option disables the SQLite’s journaling mechanism.
Benefits:
-
Reduces I/O overhead
-
Improves overall performance
-
Can be combined with EXCLUSIVE mode.
Limitations:
-
If the process is interrupted without a clean file closure, the file may be left in an inconsistent or unstable state.
-
This option must be used only for temporary data or files that can be fully rebuilt or reloaded without impact.
8.7.8. Defaults
If no values for cache sizes have been set, defaults are used. The different caches have the following default values:
| Parameters | Default Value |
|---|---|
READ |
100 |
UPDATE |
100 |
WRITE |
0 |
COMMIT |
-1 |
You can customize these default values in the Raincode Catalog file by adding a datasetSqlMappingDefault entity inside catalogConfiguration that specifies default values in the following form:
<datasetSqlMappingDefault>
<vsamUpdateCache>www</vsamUpdateCache>
<vsamWriteCache>xxx</vsamWriteCache>
<vsamPrefetch>yyy</vsamPrefetch>
<vsamCommitRate>zzz</vsamCommitRate>
</datasetSqlMappingDefault>
8.8. VSAMSql Local Copy Mechanism
8.8.1. Scope
In certain batch jobs, VSAMSql access time remains too high despite standard optimizations such as query tuning and caching. This usually happens in steps that perform a very large number of VSAMSql accesses, where the combined latency and VSAMSql processing overhead exceed the allowed execution window. In such cases, using the local copy mechanism can help significantly reduce overall execution time.
8.8.2. Principle
The local copy mechanism consists of:
-
copying a VSAMSql file to a local VSAM before job execution,
-
executing the program using the local VSAM instead of the VSAMSql file,
-
synchronizing modified data back to the original VSAMSql file after execution.
The local VSAM is exclusive to the job for the entire duration of the step.
8.8.3. Process Description
Local copy initialization
Before the execution of the step:
-
the VSAMsql file is copied to a local file system,
-
a local VSAM is created on a specified volume,
-
exclusive access to this local VSAM is enforced.
8.8.4. Applicable Scenarios
The local copy mechanism applies to:
-
batch jobs with high VSAMSql access volume,
-
programs performing intensive read and write operations.
8.8.5. Usage Constraints
-
The local VSAM must be exclusive to the job.
-
The synchronization phase must complete successfully.
-
This mechanism is intended for batch processing only.
8.8.6. Practical Usage
File Identification
When a processing step exceeds its expected execution time, identify the VSAMSql files that are responsible for the slowdown.
8.8.7. VSAMSql File Locking
Since all modifications are performed on a local copy of the file, it is recommended to lock the original VSAMSql file in order to prevent concurrent updates during program execution.
Allocating the file with DISP=OLD provides exclusive access, ensuring that no other process can update the VSAMSql file during execution and synchronization.
Using DISP=OLD maintains data integrity by avoiding situations where external processes introduce changes that would not be reflected in the local copy and could be overwritten or lost during the synchronization phase.
8.9. Profiling VSAMSql cache behavior
VSAMSql collects cache behavior statistics that can help identify performance issues and tune the cache parameters accordingly.
These statistics are logged in the log files when the logging level is set to INFO during batch job execution. For details on how to configure the logging level, refer to the LogLevel.
The information is logged to SYSOUT whenever a SQL commit is invoked, that is, when COMMITRATE is reached or when the program finishes execution.
A typical log entry looks like this:
[INFO] [VsamSqlProfiler]: ProgramReads=74, ProgramWrites=0, DBSelects=75, DBUpdates=0, DBInserts=0, DBDeletes=0, DBUnknown=0
In this example, the program sequentially reads 74 records (shown as ProgramReads) from a VSAM file. Since the prefetch cache size is set to 1, it actually performs 75 reads from the database (to account for internal operations needed by VSAMSql). If the prefetch cache is set to 100, the same program reduces database reads to just 4, as shown here:
[INFO] [VsamSqlProfiler]: ProgramReads=74, ProgramWrites=0, DBSelects=4, DBUpdates=0, DBInserts=0, DBDeletes=0, DBUnknown=0
8.10. Database isolation level
In some scenario, it is necessary to configure the isolation level (see here) of a process to a different level.
For example, consider a long-running batch job that updates data and you want to run online transactions (CICS) in parallel to read the same data. If the default isolation level is set to ReadCommitted, the batch job can lock rows or tables, preventing the online transactions from accessing the data. To avoid this, you can set the isolation level of the online transaction to Snapshot, allowing them to read the data without being blocked by the batch job.
In order to set the isolation level of a process, you need to configure an environment variable called: RC_VSAMSQL_ISOLATION_LEVEL.
The supported values are (see here):
-
Serializable
-
RepeatableRead
-
ReadCommitted
-
ReadUncommitted
-
Snapshot
-
Chaos
8.11. Command line options of VsamSql.load
Below are the details of the command line options of VsamSql.load.exe.
Load
| Command-line option | Default value | Description |
|---|---|---|
|
The catalog configuration file. If not set, use the default catalog |
|
|
The code page of the input data file. By default is the system code page |
|
|
Path to the file to be loaded This argument is mandatory. |
|
|
An XML-based descriptors for the variable declarations as produced by the DeclDescriptors of the COBOL and PL/I compiler |
|
|
The file id |
|
|
Path to place the files for bcp This argument is mandatory. |
|
|
|
The output format Valid values are:
|
|
|
The partition in which the data must be loaded |
|
|
The record format of the file, if the file doesn’t exist. Accepted values = Unknown, FB, VB, FBA, VBA |
|
The record length of the file, if the file doesn’t exist |
|
|
the name of a variable of DeclDescriptors used to define the columns |
|
|
The table’s name in which the data should be loaded |
|
|
The DSN in which the data must be loaded. It must be prefixed by the volume, for ex ":DEFALT:MY.DSN.FILE" This argument is mandatory. |
Miscellaneous
| Command-line option | Default value | Description |
|---|---|---|
|
This command-line option is an additional .net 'app.config' file. |
|
|
Displays the tool’s help information. |
|
|
||
|
|
Displays a description of the program. |
|
|
Specifies the log level. Valid values are:
|
|
|
Displays the version information. |
8.12. Command line options of VsamSql.DbGenerator
Below are the details of the command line options of VsamSql.DbGenerator.exe.
Generation
| Command-line option | Default value | Description |
|---|---|---|
|
The input catalog configuration file for generating the database scripts. If not set, use the default catalog |
|
|
An XML-based descriptors for the variable declarations as produced by the DeclDescriptors of the COBOL and PL/I compiler |
|
|
|
The output file (.sql). If catalog configuration contains more than one connection plan. One file is created by plan and the file is suffixed by the plan name |
|
The connection string to the database to check if the tables already exists. |
|
|
the name of a variable of DeclDescriptors used to define the columns |
|
|
the name table for which the creation script should be generated |
|
|
|
The target database type Valid values are:
|
Miscellaneous
| Command-line option | Default value | Description |
|---|---|---|
|
This command-line option is an additional .net 'app.config' file. |
|
|
Displays the tool’s help information. |
|
|
||
|
|
Displays a description of the program. |
|
|
Specifies the log level. Valid values are:
|
|
|
Displays the version information. |
9. JclConversion
JclConversion is a functionality that converts JCL into a new format, typically such that the converted JCL uses a different utility than what was originally specified in PGM. To activate this functionality, the option JclConverter of Submit is used.
In itself, JclConversion does not perform the conversion; instead, it delegates the core of this work to external programs. These programs are not meant to be written by the user, they are supplied by Raincode. The converted output is placed in an output directory, as specified by the configuration file discussed below.
| The result of a conversion is not automatically used by Submit in future calls of the JCL. Instead, it is the responsibility of the user to ensure that the converted JCL, which has been placed in the output directory, is used where appropriate. |
9.1. JclConverter config file
The JclConverter config file is an XML file that describes which PGM= must be converted and how to convert them. An example file is below, and it specifies that calls to SORT need to be replaced with calls to SYNCSORT and that the SYSIN DD needs to be converted by the XSORT conversion program.
<JclConverterInfo
JclConvSaveDir="outputDir">
<JclConverterPGMs>
<JclConverterPGM
PGM_ConvScript="XSORT"
PGM_ConvDD="SYSIN"
PGM_ConvExeCur="SORT"
PGM_ConvExeNew="SYNCSORT" />
</JclConverterPGMs>
</JclConverterInfo>
There is one JclConverterPGM element for each PGM to be converted. The meaning of the different attributes are:
XML Attribute |
Description |
|
Defines where the new JCL will be saved with the same name as the original one |
|
The name of the PGM to match on |
|
The new name of the PGM, after conversion |
|
DD name with the input that will be converted into the new syntax by the conversion program. This DD will have the new commands in the newly created JCL |
|
The script that will perform the conversion |
If the converted JCL already exists in the JclConvSaveDir, this file will be overwritten.
|
The JCLConverter supports only inline DD for the parameter PGM ConvDD, as it will place the result of conversion there.
|
Below are the three sample JclConverterPGM elements.
Sample 1: JclConverterPGM to convert a SORT step
<JclConverterPGM
PGM_ConvScript="XICETOOL"
PGM_ConvDD="TOOLIN"
PGM_ConvExeCur="ICETOOL"
PGM_ConvExeNew="XXXTOOL" />
Sample 2: JCLConverterPGM to convert Db2 LOAD/UNLOAD (DSNUTILB) step
<JclConverterPGM
PGM_ConvScript="XDSNUTILB"
PGM_ConvDD="SYSIN"
PGM_ConvExeCur="DSNUTILB"
PGM_ConvExeNew="RCDSNUTILB" />
Sample 3: JCLConverterPGM to convert HPU UNLOAD (INZUTILB) step
<JclConverterPGM
PGM_ConvScript="XINZUTILB"
PGM_ConvDD="SYSIN"
PGM_ConvExeCur="INZUTILB"
PGM_ConvExeNew="RCINZUTILB" />
9.2. Considerations for JCLConverter
The use of the JCLConverter has the following prerequisites:
-
The translation tools must be installed with the Raincode Stack.
-
The JCL to be converted must be executed in a working environment where the file catalog is available; files defined in JCL will be accessed within this JCL run.
-
Files will be created or updated depending on the use of their DD statements in the JCL, just like a normal execution.
-
RestartJobIDcan not be used.
In the case of a Sort SYSIN or ICETOOL TOOLIN to be converted into multiple steps (SYSINs and TOOLINs), the following changes to the JCL will apply:
-
The
JCL, will haveSYSIN1toSYSINndepending on the generatedSYSINsfrom theSortTranslatorforSORTorICETOOL. -
For the
SORT, theEXEC PGMstatement will get an additional parameter for the execution:
PARM='SYSIN=n,TEMP=n'
where SYSIN=n, is the number of SYSINs and TEMP=n is the number of used temporary files of the SYNCSORT execution.
For the ICETOOL, the EXEC PGM statement will get an additional parameter for the execution:
PARM='TOOLIN=n,TEMP=n'
where TOOLIN=n is the number of TOOLINs and TEMP=n is the number of used temporary files of the Syncsort execution.
-
The PowerShell script
SyncsortorICETOOLwill read these parameters and execute theSYNCSORT/ICETOOL.exeas required. -
All used
$ENV:DD_variableswill be replaced in this PowerShell script. TheDD_TMPfiles will be in theSYSLOGdirectory of the givenJOB.
9.3. Sample Sort
9.3.2. Output
Below is the output produced from the SORT command: submit -Jclconverter="c:\convertedJcl.xml"
//STEP03 EXEC PGM=SYNCSORT
//SYSIN DD *
/FIELDS Src_0 1 12 CHARACTER
/INFILE $env:DD_SORTIN FIXED 80
/KEYS Src_0 ASCENDING
/COLLATINGSEQUENCE DEFAULT EBCDIC
/OUTFILE $env:DD_SORTOUT FIXED 80 OVERWRITE
/*
Environment variables $env:DD_SORTIN etc. will be replaced with the actual content at execution before the SYNCSORT is called.
|
9.4. Sample SORT for multiple SYSIN files
9.4.1. Input
//STEP02 EXEC PGM=XSORT
//SYSIN DD *
JOINKEYS F1=INPUT1,FIELDS=(3,4,A,7,4,A)
JOINKEYS F2=INPUT2,FIELDS=(1,4,A,5,4,A)
JOIN UNPAIRED,F1,ONLY
SORT FIELDS=(3,20,CH,A,68,10,ZD,A)
/*
//* END
9.4.2. Output
//STEP02 EXEC PGM=SYNCSORT,PARM='SYSIN=4,TEMP=3'
//SYSIN1 DD *
/FIELDS Src_0 3 4 UINTEGER BIGENDIAN, Src_1 7 4 UINTEGER BIGENDIAN
/INFILE $env:DD_INPUT1 STREAM CRLF
/KEYS Src_0 ASCENDING, Src_1 ASCENDING
/COLLATINGSEQUENCE DEFAULT EBCDIC
/OUTFILE $env:DD__TMP1 STREAM CRLF OVERWRITE
/END
/*
//SYSIN2 DD *
/FIELDS Src_0 1 4 UINTEGER BIGENDIAN, Src_1 5 4 UINTEGER BIGENDIAN
/INFILE $env:DD_INPUT2 STREAM CRLF
/KEYS Src_0 ASCENDING, Src_1 ASCENDING
/COLLATINGSEQUENCE DEFAULT EBCDIC
/OUTFILE $env:DD__TMP2 STREAM CRLF OVERWRITE
/END
/*
//SYSIN3 DD *
/FIELDS Src_2 1 4, Src_3 5 4
/FIELDS Src_0 3 4, Src_1 7 4
/INFILE $env:DD__TMP1 VARIABLE 80
/JOINKEYS SORTED Src_0, Src_1
/INFILE $env:DD__TMP2 VARIABLE 80
/JOINKEYS SORTED Src_2, Src_3
/JOIN UNPAIRED LEFTSIDE ONLY
/OUTFILE $env:DD__TMP3 VARIABLE 152 OVERWRITE
/END
/*
//SYSIN4 DD *
/FIELDS Src_0 3 20 CHARACTER, Src_1 68 10 ZD
/INFILE $env:DD__TMP3 VARIABLE 152
/KEYS Src_0 ASCENDING, Src_1 ASCENDING
/COLLATINGSEQUENCE DEFAULT EBCDIC
/OUTFILE $env:DD_SORTOUT FIXED 80 OVERWRITE
/END
/*
//* END
9.5. Possible error messages
-
JclConverter JclConvDDis not set -
JclConverter JclConvExeCuris not set -
JclConverter JclConvExeNewis not set -
JclConverter JclConvPgmNamenot found as an EXE in this JCL -
JclConverter JclConvSaveDirmust be different from jclFilePath -
JclConverter JclConvSaveDiris not set or empty -
JclConverter JclConvScriptis not set -
JclConverter JclConverterPgmsis not set or empty -
JclConverter JclConverterXMLfile not found or error -
JclConverter JclFilePathnot set. Have to abend,Submitmust be called with a file parameter -
JclConverter RestartJobIDmust not be used if JclConvert is used
10. JCL Error codes
Raincode JCL introduces a few Return codes, as mentioned in this section.
Error codes |
Description |
|
Error return code value to be used to determine if a higher return code should be set in a certain error condition. |
|
The return code of the process when it is out of memory due to a REGION parameter violation. |
|
Default return code when ShouldRun indicates the job should not run. |
|
STEP was skipped by condition |
|
PGM not found when CONTROLM is set, report error -27 and continue. Also, refer to RCS806PgmNotFound = 806 |
| Error codes | Description |
|---|---|
|
DCB argument Error |
|
Argument exception error |
|
The default ABEND return code when triggered by error conditions controlled by batch - not used for program ABENDs |
|
CTRL = C abend S122 |
|
JCL Error Dataset already exists |
|
Access error PDS Member |
|
PGM not found abend S806 when CONTROLM is not set issue this error and stop processing |
|
The default return code for PROC must be different when correctly set in all cases |
|
The default return code for STEP must be different when correctly set in all cases |
|
The default return code for JOB must be different when correctly set in all cases |
|
JCL ERROR JOB NOT RUN - JCL ERROR JOB HAS NO STEPS |
|
Invalid dataset name specified |
|
Invalid DISP=SHR IEF286I DISP FIELD INCOMPATIBLE WITH DSNAME |
|
SDSN_WAIT Abend Timer |
|
No steps have been executed for this job |
|
Non existent GDG or PDS |
|
Conflicting DCB Parameters |
|
DSN Metadata file missing or corrupt |
|
DSN duplicate already exiting |
|
JclConverter Error see the message |
|
Error in the STEP StartTime/EndTime maybe some fields are not set correctly |
|
Return code for SUBMIT Return code not handled somewhere else |
|
Return code for Submit to return if an internal error occurs |
|
Rclrun error 9000 - 8192 = S808 |
|
Abend by compiler COBOL / PLI / HLASM 9080 - 8192 = S888 |
|
Command line parsing error 9081 - 8192 = S889 |
|
|
|
|
|
11. Submit For Developers
Some elements of Submit are targeted towards developers, so they are presented in this section.
11.1. Environment variables defined by Submit
For each step that is executed, Submit defines several environment variables, which are available to the program that is executed during that step.
| Environment Variable | Description |
|---|---|
RC_JOB_ID |
Contains the value of the option |
RC_STEP_ID |
Current executing StepID |
RC_JOB_NAME |
Current executing Job Name |
RC_LegacyRunner |
Legacy runner path for COBOL, PL/I, Assembler DLL. The default value is |
RCBATCHDIR |
Path to Raincode JCL binary from where |
RC_DB_CONNECTION |
connection string defined. Utilities like |
RC_DB_TYPE |
DB Type associated with the connection String |
RC_JOB_RESTARTED_ID |
Contains the value of the option |
… < From Raincode.Catalog.xml > |
All Environment variables defined in |
In addition to the above, Submit defines environment variables for each DD that it treats when executing a JCL step. These start with DD and end with the name of the DD, as shown in the table below.
| Environment Variable | Description |
|---|---|
DD_<name> |
The path to the file, or a semicolon-separated list when there are multiple. |
DDDISP_<name> |
The disposition of the DD. |
DDLRECL_<name> |
The Record Length. |
DDRECFM_<name> |
The Record Format. |
DDMETAKEEP_<name> |
Flag whether to keep the meta file or not. |
DDMETA_<name> |
The path to the meta file, when kept. |
DDPARAM_<name> |
Extra driver parameters. |
11.2. Debugging batch jobs
To enable the debugging of the execution of a JCL, i.e. a batch job, Submit includes the ability to increase execution trace information, as well as to use the .Net SDK debugger.
11.2.1. Increasing log information: use Trace
Increase the LogLevel to increase details in the log messages produced by the execution of the program. -LogLevel=TRACE provides very detailed information on what Submit is doing. Add -LogToConsole to output logs to the console instead of MSGLOG.txt.
11.2.2. Debug at .Net Level
If the Trace logs do not help, you may consider debugging a batch job at the .Net level. This, of course, presupposes that the full SDK is installed. Two levels of debugging are possible: the job level and the step level.
Debug Job
Running submit with the -DebugSubmit=true flag will cause execution to break before any steps are executed. An SDK debugger window will pop up and open. Select the source code you wish to debug and attach the debugger. The breakpoint will hit when the source is executed for any of the steps.
Debug Step
Running Submit with the -DebugStep=STEPNAME will cause the execution to break just before the given step. An SDK debugger window will pop up and open. Select the source code for the step executable to debug and attach the debugger.
11.3. Timeshift
Timeshift testing is needed to test how a job behaves in the future or the past. The Raincode legacy runtime provides a way to perform Timeshift testing by letting you modify the date and time retrieved by the job when executing.
Timeshift can be:
-
absolute by defining an initial date and time for the run or
-
relative by defining a date time offset relative to the current time.
If RC_DATETIMEOFFSET is defined (in the format of C# TimeSpan), this offset is added to DateTime.Now when the Date/Time is read by all the steps.
If RC_DATETIMEOFFSET is not defined, the runtime checks (only once) the environment variable RC_INITIALDATETIME.
Suppose RC_INITIALDATETIME is defined (in the format of C# DateTime). In that case, the runtime computes the DateTime offset between now and the provided value and sets the RC_DATETIMEOFFSET environment variable to ensure that the called program/step uses the same offset.
Submit program accepts the command line parameter -InitialDateTime to set up the Initial DateTime/offsets.
| These rules and environment variables also apply to Raincode legacy stack runtime. For more details, refer to Timeshift. |
12. Plugins
12.1. Introduction
To support an extensible and customisable system that adapts to client’s needs, Raincode has a plugin system that pervades the entire toolset. This section presents the plugin mechanism for plugin implementers.
In terminology:
-
A plugin is a piece of software that adds specific functionality to the toolset without altering its core.
-
A plugin hook is the specific point in the toolset’s execution where the toolset calls the plugin.
-
The entry point is the method that receives the initial call to the plugin hook.
A hook calls its plugin according to the API that is defined for that specific kind of plugin. This API can be typed using an interface or an abstract class; i.e., a plugin implements that interface or abstract class. All hooks have a default plugin attached and include a strategy on how to decide which plugin to call at runtime. These strategies are defined later in this document, in Entry Point Strategies.
A plugin is provided as a dll. To load a plugin in a certain tool, use the argument -Plugin, or -PluginPath, or drop the plugin assembly in the default plugin path for the tool (which is documented on a tool-by-tool basis).
12.2. Implementing a Plugin
Plugins are at the heart of the Raincode toolset, conceptually and in practice: the mechanism is defined in Raincode.Core.Plugin namespace inside of the rccorelib library, i.e. in the core library of the toolset. There are two different kinds of plugins:
-
Action plugins are plugins that perform a single action and do not hold any state nor return any value when the action is triggered, i.e. the entry point of the plugin is a method with a void return type.
-
Normal plugins are plugins with a possibly more complex API. The entry point of the plugin returns a value that is of the type expected by the hook. The hook will then use this value according to the declared API.
| Some more terminology: a bootstrap function is a function of the plugin that is called at startup of the runtime, and is responsible for registering the plugin with its hook (after initialization, if needed). |
Bootstrapping a plugin
The assembly of the plugin needs to inform the runtime of its bootstrap function, so that this bootstrap function can be called when the runtime is initialized. To do this, an assembly attribute of the following form needs to be added:
[assembly:PluginProvider(typeof(NameSpace.To.Plugin.Plugin),"BootstrapPlugin")]
where the first parameter (NameSpace.To.Plugin.Plugin) is the type of the class of the plugin, and the BootstrapPlugin static method named in the second parameter is the bootstrap function of the plugin.
The Raincode tools will call the BootstrapPlugin static method right after loading the assembly. This method should then perform intialization, if needed, and register itself with the correct hook. To do the latter, it calls the static Provide method of the intended plugin hook. For example, in the case of creating a Qix Factory plugin, this would be:
RaincodeLegacyQixInterface.QixInstances.QixFactory.ConstructorPlugin.Provide(priority, delegateMethod)
The Provide method takes two parameters: a priority value and a .NET delegate type (i.e. a method signature) for the entry point of the plugin. The priority is used in the entry point strategy of the hook. Each hook will have its own type of delegate, i.e. its own type for the entry point of the plugin. Documentation of the types of hooks and the signature of the entry point is explained in the Plugin hook section.
Calling of Plugins
From this point on, whenever a hook needs a plugin it will call the appropriate registered entry point, as defined by its Entry Point Strategy.
Depending on the type of plugin hook, the entry point method receives different types of arguments. The types and values used by the plugin hooks are described (semi-formally) in their corresponding sections of the documentation, and the plugin hook section explains how to read these descriptions.
To continue the QixFactory example, a possible entry point is the following Builder method, which simply instantiates a new factory with the given QIX context:
public static QixFactory Builder(IQixContext context){
return new MyQixFactory(context);
}
Once a QixFactory has been initialized in this way, the methods on this object will be called according to the API for the plugin (as explained in the plugin hook section).
12.3. Examples
This section provides a few example plugins to illustrate various features of the plugin mechanism.
Action Plugin: Execution Context Preparing
This plugin is called after an execution context has been initialized. It gets as arguments the newly initialized context and the name of the entry point of the called COBOL or PL/I code.
The example implementation below simply adds an informational line to the log in the PostInit method. This method is registered as an entry point in the Register method, and the assembly properties declare this class as a plugin with the Register method as the bootstrap function.
[assembly: PluginProvider(typeof(MyExtraLog.ExCPLogger), "Register")]
namespace ExCPLoggerNS
{
public class ExCPLogger
{
public static void Register()
{
ExecutionContext.PreparePlugin.Provide(100, PostInit);
}
private static LogSource src = new LogSource("Ctx prep logger");
public static void PostInit(ExecutionContext ctx, string entry)
{
Logger.LogInfo(src, $"New context created for entry point {entry}");
}
}
}
Password rewriter
The password rewriter plugin serves as an example of a basic plugin: the entry point receives a connection string and should return a connection string with the password rewritten to the required value. The hook for the password rewriter is present throughout the toolset. Basically, everywhere a connection string is used, this plugin will be called before the connection is made.
The example below shows such a password rewriter plugin. It replaces !PASSWORD! with a hard-coded value, as can be seen in the body of the MapPassword method.
[assembly: PluginProvider(
typeof(OwnPasswordRewriter.OwnPasswordRewriterSample),
"Register")]
namespace OwnPasswordRewriter
{
public class OwnPasswordRewriterSample
{
public static void Register()
{
RainCodeLegacyRuntimeUtils.PasswordMapping.PasswordRewriter.Provide(10, MapPassword);
}
private static string MapPassword(string connectionString)
{
return connectionString.Replace ("!PASSWORD!", "myNoLongerSecretPassword");
}
}
}
DumpProcessor
The DumpProcessor plugin is an example plugin that shows the use of a more complex API: the entry point should create an instance of BaseDumpProcessor, and this will later be tasked to provide functionality for specific parts of a program dump.
The example below shows how the entry point simply returns an instance of the MyDumper class. Then the different method implementations of the abstract methods declared in BaseDumpProcessor take care of producing an XML document for the dump. Note the Exception method; it gets the underlying runtime exception triggered by the faulty code. This illustrates how (deeply) internal elements can be exposed to plugins, to be treated as required by the plugin.
[assembly: PluginProvider(typeof(DumpProcessPlugin.MyDumper), "RegisterMyDumper")]
namespace DumpProcessPlugin
{
public class MyDumper : BaseDumpProcessor
{
const string FILENAME = "dump.xml";
XDocument doc;
Stack<XElement> elems;
public static void RegisterMyDumper()
{
ConstructorPlugin.Provide(10, NewDumper);
}
public static MyDumper NewDumper(ExecutionContext ctx)
{
return new MyDumper();
}
public override void Start()
{
doc = new XDocument();
elems = new Stack<XElement>();
doc.Add(new XElement("dump"));
elems.Push(doc.Root);
}
public override void End()
{
doc.Save(FILENAME);
}
public override void Exception(Exception e)
{
doc.Root.Add(new XElement("exception", e.Message));
}
public override void CurrentStatement(string position)
{
doc.Root.Add(new XElement("position", position));
}
[...]
}
}
DB connection plugin
Some use cases require sending specific commands to the DB when opening or closing a database connection. To allow for this, Raincode JCL lets you implement a C# plugin that will be called just after the call of Open function and just before the call of Close. It will be given the instance of System.Data.Common.DbConnection that represents the connection.
Sample Plugin implementation
using System;
using System.Data.Common;
using RainCode.Core.Logging;
using RainCode.Core.Plugin;
[assembly: PluginProvider(typeof(Raincode.Tests.DbConnectionPlugin), nameof(Raincode.Tests.DbConnectionPlugin.Register))]
namespace Raincode.Tests
{
public class DbConnectionPlugin
{
private static LogSource LogSource = new LogSource("DbConnectionPlugin");
public static void Register()
{
Logger.LogInfo(LogSource, "Registering QueryTranslation");
Raincode.Batch.Utilities.Database.DatabaseConnection.BatchSQLConnectionCreate.Provide(10, ConnectionCreate);
Raincode.Batch.Utilities.Database.DatabaseConnection.BatchSQLConnected.Provide(10, ConnectionOpen);
Raincode.Batch.Utilities.Database.DatabaseConnection.BatchSQLDisconnect.Provide(10, ConnectionClose);
}
private static DbConnection ConnectionCreate(DbConnection arg)
{
// manage the connection after create and before open
Console.WriteLine("ConnectionCreate");
return arg;
}
private static DbConnection ConnectionOpen(DbConnection arg)
{
// manage the connection after open
Console.WriteLine("ConnectionOpen");
return arg;
}
private static DbConnection ConnectionClose(DbConnection arg)
{
// manage the connection Before close
Console.WriteLine("ConnectionClose");
return arg;
}
}
}
Custom Plan Mapping
In some situations, the dbConnectionDataProvider file (see Map a PLAN name to a connection string) will be insufficient to map a PLAN name to the actual connection string.
To address that limitation, Raincode JCL lets you implement a C# plugin that implements a custom mapping scheme. It is called right after the resolution of the PLAN name with two parameters:
-
The PLAN Name
-
Then proposed connection string, as resolved by Submit.
It returns a string, which is the connection string that will be used.
Example uses for this plugin are:
-
Implementing a custom PLAN to connection string mapping
-
Retrieving a password and patch the connection string with the actual password to use
Sample plugin implementation
A sample for the C# plugin: DbConnectionMapperSample is available in the samples directory in the Raincode JCL installation directory. The code of this sample is as follows:
using RainCode.Core.Plugin;
using System;
[assembly: PluginProvider(typeof(DbConnectionMapperSample.DbConnectionMapperPasswordSample), nameof(DbConnectionMapperSample.DbConnectionMapperPasswordSample.Register))]
namespace DbConnectionMapperSample
{
public class DbConnectionMapperPasswordSample
{
public static void Register()
{
Raincode.Batch.Common.DbConnectionDataProvider.ConnectionMappingPlugin.Provide(10, MapPassword);
}
private static string MapPassword(string plan, String proposed_connectionString)
{
/* Here retrieve the connection string */
/* return null if no patch is possible */
if (plan == "test")
return = "Your special connection string";
else return proposed_connectionString;
}
}
}
Password Plugin
Another problem with the dbConnection provider file (see Map a PLAN name to a connection string) is that the file storing the connection strings will contain passwords in plaintext.
To address this limitation, Raincode JCL lets you implement a C# plugin that will be called just before executing the connection call to the database layer. Its purpose is to retrieve the actual password, and as this is called at the latest moment, the actual connection string (including the password) will not appear in any log file.
The basic usage scheme is to create a dbConnection provider file (or a custom plan mapping plugin) that stores the full connection string where the password is a pattern that is easy to match. These patterns will then be replaced at the latest moment by the actual password retrieved via your security process in the plugin.
If used please ensure to add -Plugin=<assembly> -PluginPath=<path> in your custom rclrun.args file and add these to .args files to batch utilities that would need to connect the database (like DNSUTILB, …).
Sample Plugin implementation
A sample implementation of this plugin is as follows:
using RainCode.Core.Plugin;
using RainCodeLegacyRuntimeUtils;
[assembly: PluginProvider(typeof(OwnPasswordRewriter.OwnPasswordRewriterSample), nameof(OwnPasswordRewriter.OwnPasswordRewriterSample.Register))]
namespace OwnPasswordRewriter
{
public class OwnPasswordRewriterSample
{
public static void Register()
{
RainCodeLegacyRuntimeUtils.PasswordMapping.PasswordRewriter.Provide(10, MapPassword);
}
private static string MapPassword(string connectionString)
{
/* Here patch the connection string with correct password */
/* return null if no patch is possible */
string res = connectionString.Replace ("#PASSWORD#", "myPassword");
return res;
}
}
}
Custom Interface Configurations
The behavior of Raincode JCL can also be customized programmatically by providing C# implementations of a number of interfaces.
The default application configuration is located in the installation directory, submit.exe.config. The JCL runtime uses Autofac to register types for the various interfaces that are supported.
Raincode.Batch.Runtime.IExecutionController
-
This interface is called before and after steps, and jobs are executed.
-
This interface is useful to implement if custom logging, tracing, or individual step inspection is required.
-
The
submit.exe.configcontains the registration for theDefaultExecutionController, which does nothing. -
Replace the class specified in the
<autofac>/<components>/<component>element forIExecutionControllerto register a custom class. (e.g.,<component type="Raincode.Batch.Runtime.DefaultExecutionController,Raincode.Batch.Runtime" service="Raincode.Batch.Runtime.IExecutionController,Raincode.Batch.Runtime">)
Raincode.Batch.Jcl.Interfaces.IJclPreprocessor
-
This interface is called before and after
AutoEditvariables are replaced in the input stream, and called to set/modify/update theSUBSTVARdictionary variables. -
The
submit.exe.configcontains the registration for the DefaultPreProcessor, which does nothing. -
Replace the class specified for
IJclPreprocessorto register a custom class.(e.g.,<component type = "Raincode.Batch.Jcl.DefaultPreProcessor,Raincode.Batch.Jcl" service= "Raincode.Batch.Jcl.Interfaces.IJclPreprocessor,Raincode.Batch.Jcl">;)
Raincode.Batch.Runtime.IExecuteSecurity
-
This interface is called to determine if a user can run a job, submit a particular dataset, or submit a particular file.
-
It operates independently of standard Windows security
ACLsthat can be set on volumes/files. -
The
submit.exe.configcontains the registration for theDefaultExecuteSecurityclass, which returns true for each of the methods allowing any job or dataset to be submitted. -
Replace the class specified for the
IExecuteSecurityservice in thesubmit.exe.configfile with a custom class.(e.g.,<component type="Raincode.Batch.Runtime.DefaultExecuteSecurity,Raincode.Batch.Runtime" service="Raincode.Batch.Runtime.IExecuteSecurity,Raincode.Batch.Runtime">;)
Raincode.Batch.Runtime.IPrintHandler
-
This interface is called to control the spooling of outputs to a printer/file/other destination.
-
This element uses the name attribute to specify the name of the output class to map to the custom print handler.
-
There are three separate print handlers that are provided, which are documented in the
submit.exe.configfile. (e.g.,<component type="Raincode.Batch.Runtime.DefaultPrintHandler,Raincode.Batch.Runtime" service="Raincode.Batch.Runtime.IPrintHandler, Raincode.Batch.Runtime" name="A">;Registers the default print handler (will print to the default printer on the machine for output class A. ) -
When a
SYSOUTitem is spooled with the default print handler, it will read theASAcontrol character and advance the appropriate number of lines/pages before writing the output.
UserWaitForFilePlugin
A sample code snippet is provided below:
Registration of the plugin: DataSetMetaPersistenceFile.UserWaitForFilePlugin.Provide(10, OwnWaitForFile);
internal static int waitcount = 0;
internal static string lastname = "";
// return True = try to read again
// return False = continue with the status file not found
private static bool OwnWaitForFile(string Fullpath, FileMode fmode, FileAccess faccess, Exception ex)
{
//check for file with the name ZFMGTE\\#0001 and retry two times
if (lastname != Fullpath)
{
lastname = Fullpath;
waitcount = 0;
}
if (Fullpath.Contains("ZFMGTE\\#0001"))
{
if (waitcount >= 2)
return false;
waitcount++;
return true;
}
return false; // This is the default
}
12.4. Global Plugins Settings
Some plugins are required across all Raincode tools.
A common example is a Password Plugin, which may be needed for every application and tool.
You can define two environment variables to configure plugins that will be automatically loaded by the runtime, as mentioned below:
RC_DEFAULT_PLUGIN
RC_DEFAULT_PLUGIN = plugin1;plugin2,param2;..
Format:
pluginName1[,parameter1][;pluginName2[,parameter2]…]
-
Plugins names are separated by a semicolon (;).
-
Specify the plugin name without the .dll extension.
-
Optional parameters can be provided after a comma.
RC_DEFAULT_PLUGIN_PATH
RC_DEFAULT_PLUGIN_PATH = path1;path2;…
Format:
path1[;path2…]
-
Paths are separated by a semicolon (;).
-
These paths define where the runtime will look for plugin binaries (.dll files).
| This feature is available in version 5 starting from 5.0.399, and in version 6 starting from 6.0.33. |
13. Raincode Plugins
13.1. Plugin Hook Documentation
There are many plugin hooks present in the Raincode toolset, and they are described at the relevant locations throughout the documentation. To better understand these descriptions, the following text is included at each location.
Generated Hook Descriptions
Descriptions of the Raincode Plugin hooks are automatically generated, based on annotations made in the source code of the hooks. This section explains how to interpret those descriptions.
The generated documentation can include up to three parts: the hook description (mandatory), the plugin API documentation (optional), and the plugin description (optional).
The hook class description
This is a table that contains up to three rows:
-
Field/Property with hook object: The location of the hook.
-
Default implementation: describes the behavior of the default plugin in plain text.
-
Strategy: the kind of entry point strategy (for more details, refer to Entry Point Strategies).
Plugin API
This reveals at a minimum the root of the API specification of the plugin: the signature of the entry point of the plugin.
Apart from this signature, the API section may also contain a textual description of the characteristics of the API, e.g. describing the roles of the different methods in the returnType.
Plugin Description
This is a (brief) textual description of what the intended functionality of the plugin is.
Entry Point Strategies
When a plugin hook encounters multiple registered plugins, a decision is made on which of these plugins is (the most) suitable. The hook is hard-coded to use a specific strategy to make this choice. To clarify the meaning of these strategies, they are documented here.
Strategies are subclasses of the RainCode.Core.Plugin.Strategy class, and there are multiple strategies defined out-of-the-box:
-
Strategy.Best: This is the default strategy for plugins that return a result. This strategy only calls the highest priority implementation.
-
Strategy.ExecAll: This is the default strategy for action plugins. It calls all the implementations by decreasing priority.
-
Strategy.BestNonNull<R>: This calls entry points by decreasing priority until a non-null result is found. The return type of the entry point must be a class or interface.
-
Strategy.BestWithValue<R>: This calls entry points by decreasing priority until HasValue on the return value is true. The return type of the entry point must be a nullable value type.
-
Strategy.All: This calls entry points by decreasing priority until
falseis returned. -
Strategy.Any: This calls entry points by decreasing priority until
trueis returned.
| The priority of the default plugins is zero. |
13.2. List of Raincode Plugins
13.2.1. IdcamsDelete
Class |
|
Field name |
|
Strategy |
Best |
Default implementation |
The default implementation doesn’t change the |
Plugin API:
Raincode.Batch.Utilities.Idcams.DeleteParams(Raincode.Batch.Utilities.Idcams.DeleteParams params)
-
params
Description:
Allows to modify DeleteParams structure. For example set Dirdel to true to delete the directory instead of each file for the pattern "name.*". An example can be found in test case Raincode.Tests.Idcams.RutimeTestsIdcams_Internal.RCO_1157286726_DELETE_DIR_PLUGIN
13.2.2. UserCommentBuilder
Class |
|
Field name |
|
Strategy |
Best non null |
Plugin API:
string(Raincode.Batch.Runtime.Step arg0 ,string arg1)
Description:
Build custom comment string. This string is passed as -Comment=”xxx” to Cobol program
13.2.3. SaveJCLListing
Class |
|
Field name |
|
Strategy |
Best |
Default implementation |
The basic implementation save on file in Job Sysout folder |
Plugin API:
string(RainCodeLegacyBatchCatalog.Manager arg0 ,string arg1 ,string arg2 ,System.Collections.Generic.List<string> arg3)
Description:
Save the listing of the actual JCL (proc expanded, etc).
13.2.4. ReadSavedJCLListing
Class |
|
Field name |
|
Strategy |
Best |
Default implementation |
The basic implementation read from file in Job Sysout folder |
Plugin API:
System.Collections.Generic.List<string>(RainCodeLegacyBatchCatalog.Manager arg0 ,string arg1 ,string arg2)
Description:
Read the listing of the the restarted job.
13.2.5. SaveJobState
Class |
|
Field name |
|
Strategy |
Best |
Default implementation |
The basic implementation save on file in Job Sysout folder |
Plugin API:
bool(RainCodeLegacyBatchCatalog.Manager arg0 ,string arg1 ,string arg2 ,string arg3)
Description:
Save the json image of the current job status. Used for restart and saved between every step.
13.2.6. ReadSavedJobState
Class |
|
Field name |
|
Strategy |
Best |
Default implementation |
The basic implementation read from file in Job Sysout folder |
Plugin API:
string(RainCodeLegacyBatchCatalog.Manager arg0 ,string arg1 ,string arg2)
Description:
Read the json image of the restart job status.
13.2.7. BatchSQLConnectionCreate
Class |
|
Field name |
|
Strategy |
Best non null |
Default implementation |
Basic implementation does nothing |
Plugin API:
System.Data.Common.DbConnection(System.Data.Common.DbConnection DbConnection)
-
DbConnection- The created DbConnection -
Result - A (possibly updated) DbConnection
Description:
When a batch utility like DSNUTILB open a SQL connection the plugin is called to enable custom operation on connection after the connection creation .
For more details refer to the DB connection plugin documentation.
13.2.8. BatchSQLConnected
Class |
|
Field name |
|
Strategy |
Best non null |
Default implementation |
Basic implementation does nothing |
Plugin API:
System.Data.Common.DbConnection(System.Data.Common.DbConnection DbConnection)
-
DbConnection- The opened DbConnection -
Result - A (possibly updated) DbConnection
Description:
When a batch utility like DSNUTILB open a SQL connection the plugin is called to enable custom operation on connection after the connection is open.
For more details refer to the DB connection plugin documentation.
13.2.9. BatchSQLDisconnect
Class |
|
Field name |
|
Strategy |
Best non null |
Default implementation |
Basic implementation does nothing |
Plugin API:
System.Data.Common.DbConnection(System.Data.Common.DbConnection DbConnection)
-
DbConnection- The DbConnection to be closed -
Result - A (possibly updated) DbConnection
Description:
When a batch utility like DSNUTILB open a SQL connection the plugin is called to enable custom operation on connection before the connection close.
For more details refer to the DB connection plugin documentation.
14. Writing utilities
Raincode provides support for developers writing JCL utilities with the following:
-
A JCL grammar for the PEG parser generator,
-
Two classes that implement useful functionality for the utilities
-
Three utility implementations as samples.
The class Raincode.Batch.Utilities.Common.BaseOptions manages command-line options common to all batch utilities.
| Attributes | Description |
|---|---|
|
A recognized Argument set is needed to add your arguments. |
|
Catalog Manager builds on the given - CatalogConfiguration parameter or on |
|
Some Raincode utilities can run in Scan mode and log information into a repository. |
The class Raincode.Batch.Utilities.Common.BaseUtility is the base root class for batch utilities.
| Attributes | Description |
|---|---|
|
Options parsed: This class contains a property |
|
LogSource to be used when using |
| Method | Description |
|---|---|
|
The class constructor uses a boolean parameter that informs the base class if the utility will use Raincode Stack assembly. If true, path %RCDIR%/bin is added as the assembly resolution path. |
|
This is the entry point of your utility. This method is called once all parameters are parsed and |
|
The method is to be called (most of the time trivially) by the main entry point of the executable. This method takes care of parsing parameters and calls the Execute. |
The main class of a utility should look like this:
using Raincode.Batch.Utilities.Common;
using RainCode.Core.CommandLine;
using RainCode.Core.Logging;
using RainCodeLegacyBatchDataset;
using System;
using System.IO;
namespace Raincode.Batch.Utilities
{
[RCProductGroupAttribute("Raincode.Batch.Utilities")]
public class MyOptions : BaseOptions
{
public MyOptions()
{
// Your own options
SupportedArguments.SupportArg(new StringArg("MyFlag")
{
Description = "Your own Option.",
Action = val => { MyFlag = val; },
Category = "General"
});
}
public string MyFlag { get; set; }
}
public class MyUtility : BaseUtility<MyUtility, MyOptions>
{
// Main program entry call BasicMain unless you need special processing
static void Main(string[] args) => BasicMain(args);
public MyUtility() : base(needRuntime: false) { }
protected override void Execute()
{
// This is the main procedure of your Utility.
// The return code should be placed in Environment.ExitCode
Logger.LogInfo(LogSource, "MyUtility starting");
// Retrieve your Input in SYSIN
Logger.LogTrace(LogSource, "Reading SYSIN");
DataSet systsin = UtilityOptions.CatalogManager.FindKnowDDName("SYSIN");
if (systsin == null)
{
throw new FileNotFoundException("Input file SYSIN not found");
}
//TODO add your utility code here
throw new NotImplementedException("TODO not implemented!");
}
}
}
The Sample directory provides you with the implementation of three utilities you may use as a template for your utilities.
15. Samples
15.1. Creating and running a Job from C#
The following sample describes how to create a job from C# code and execute it using the SubmitRunner class from the Raincode.Batch.Submit assembly.
15.1.1. Job Setup and Execution
The first step in creating a job is to allocate a Catalog Manager object. This is used to generate the unique Job ID and is used throughout the execution of the job to query and manage datasets. Next, the job object is built up, and finally the SubmitRunner.Execute() method is called to execute the job.
Below is a sample job being constructed:
var catMan = new Manager();
Job job = new Job("MYJOB",catMan,catMan.AllocateJob());
var step1 = ProgramStep.CreateProgramStep("STEP1","IEFBR14",job.ID);
job.AddStep(step1);
step1.AddDD(new DD()
{
RecordFormat = RecordFormat.FB,
DSN = "TEST.FILE",
Disposition = new Disposition()
{
Mode = DispositionStatus.MOD,
Normal = DispositionType.CATLG,
Abnormal = DispositionType.DELETE
},
RecordLength = 80,
Volume = "DEFAULT"
});
var options = new Submit.Options();
var ret = Submit.SubmitRunner.Execute(new Submit.Options(), job);
It is important to remember that the step is added to the job object by calling AddStep. This is so the step can be configured to run in the job correctly. Also, note that AddDD is called on the step to add a DD object instead of adding directly to the collection. This is required so the DD can be properly configured for the step.
15.2. Serializing a Job for Remote Execution
To serialize a job for remote execution, call the Job.SerializeJob() method passing in a constructed Job object that has not been executed yet. It will return a JSON encoded string that can be sent to another machine (via web service, file, or other IPC mechanism). Deserialization is
handled by Job.DeserializeJob(), however additional setup is required to make it ready to execute.
The code below shows an example:
// Job is created from C# or from parsed JCL
var serialized = Job.SerializeJob(job);
// The serialized variable now contains the string representing the job
//On the other machine/instance:
var deserialized = Job.DeserializeJob(serialized);
var catMan = new Manager();
jobId = catMan.AllocateJob();
deserialized.ResetState(catMan,jobId);
Submit.SubmitRunner.Execute(new Submit.Options(), deserialized);
15.3. Customizing Submit
The submit process can be customized by implementing a console application that creates an instance of the Options() class to parse the command-line parameters, then call SubmitRunner.Execute() and return the return code.
Below is a sample implementation:
namespace Raincode.Batch.Submit
{
internal class Program
{
private static int Main(string[] args)
{
var opts = new Options();
opts.Parse(args);
return SubmitRunner.Execute(opts);
}
}
}
15.4. Customizing Logging
The batch runtime process uses the RainCode.Core.Logging.Logger class to route log messages to the appropriate source. By default, a logger is registered that outputs messages to the default Trace listener. Additionally, the -LogToConsole option for submit will register a ConsoleLogger that will output log events to the console. Output can be captured by adding a .NET configuration section to the submit.exe.config (or appropriate application configuration file), such as:
<system.diagnostics>
<trace autoflush="true" indentsize="4">
<listeners>
<add name="myListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="TextWriterOutput.log"/>
<remove name="Default"/>
</listeners>
</trace>
</system.diagnostics>
Alternatively, a custom logging class can be registered in a custom Submit executable. For instance, this implementation of Submit.exe adds a ConsoleLogger source:
namespace Raincode.Batch.Submit
{
internal class Program
{
private static int Main(string[] args)
{
RainCode.Core.Logging.Logger.CreateAndRegister<RainCode.Core.Logging.ConsoleLogger>();
var opts = new Options();
opts.Parse(args);
return SubmitRunner.Execute(opts);
}
}
}
To control the log level that is set, refer to the -LogLevel command-line option.
15.5. JCL Containerization
In the sample RaincodeJCLWrapper, the steps to containerize a JCL are demonstrated. This involves creating a REST API that accepts input parameters such as JobName and JobId, and returns the JobId of the submitted job as output.
As shown below, the jclOptions, the path for the file storage, the path for the catalog manager and jobid are defined. In the later part, submitRunner.Execute is called with the jclOptions to run a JCL.
For more details, refer to Submit.
15.5.1. Prerequisites
-
Raincode JCL compiler image
-
Raincode JCL runner image
-
Raincode license - Must be added to the
RaincodeJCLWrapperproject.
For more details on loading the Raincode JCL compiler and JCL runner image, refer to load the desired image.
15.5.2. Build Docker Image
The screenshot below is a dockerfile that creates an image to containerize the JCL runner.
Through the Visual Studio solution, open the developer command prompt and navigate to the location of the dockerfile and issue the command docker build, as shown in the screenshot below:
Once the build is successful, it will generate an image. The image can be seen through the command prompt, as shown in the screenshot below.
| Make sure that the docker desktop is running. |
15.5.3. Run Docker container
The docker run command runs a container from the image and runs on the port specified (8080).
The file volume mount option lets us mount a local machine volume to a particular path inside the container so that the container can access the file volume.
As the screenshot below shows, the FileStorage volume has been successfully mounted from the local system to the container’s app/FileStorage location.
After the file mount, the container is able to access files from the local machine. The container can access the Catalog, Jcls and Program executables.
Below is the sample Raincode.Catalog.xml that describes the configuration for the Submit runner. For more details, refer to the Catalog configuration.
15.5.4. Run a sample JCL
The above running docker container is called to execute JCLHELLO.JCL, which invokes HELLO.cob to print a SIMPLE HELLO WORLD message.
Since the jclwrapper container is running on port 8080, the API must be invoked using an HTTP client such as Postman. The screenshot below shows that the request to execute JCLHELLO.JCL was sent and the job id JOB0000000001 was received as a response.
Also, you can see the job log from the container.
You can examine the output on the local system from the folder SYSOUT. You can check MSGLOG.txt for the details.
If you look at the app/Filestorage location inside the container, you see the necessary folder created by the Submit runner and the job log for the JCL, as shown in the screenshot below.
16. Telemetry
16.1. Introduction
This section describes Raincode’s approach to Telemetry across all relevant products.
| For the sake of readability of the documentation, this section is repeated identically in the following manuals: QIX, IMSql, and JCL. |
16.1.1. What is Telemetry
According to Wikipedia, Telemetry is the automatic process of measuring and transmitting data for the purpose of monitoring applications and assessing their health and performance.
This definition implies the clear separation between the production of this continuous stream of data and the collection, summarization, storage, etc., of this data. As a response to this separation, the OpenTelemetry standard has emerged, enabling a vibrant market for visualization and monitoring tools. It provides a single, open-source standard and a set of technologies to capture and export metrics, traces, and logs from cloud-native applications and infrastructure.
16.1.2. How about Raincode
Telemetry applies to the subset of Raincode’s products that include a runtime component:
-
QIX, Raincode’s CICS emulator
-
IMSql, Raincode’s IMS emulator (and in the context of Telemetry, focusing on the IMS/TM part of this product)
-
Raincode JCL.
While very different in functionality, these products share the ability to send events that can be used to monitor the health and performance of the running processes.
While the Raincode Console can be used to manage the static aspects of the configuration of these products and some more dynamic aspects (inspecting IMS/TM queues, for instance), it does not offer any telemetry capabilities. This is not an oversight: the Raincode product line is designed to connect to third-party solutions for Telemetry instead.
Further, the section below explains how the Raincode products mentioned above can be configured to external telemetry services for monitoring, visualization, alerts, and more.
16.2. In practice
The Raincode products are agnostic as per the telemetry platform (or even Telemetry standard) they will connect to.
Using user-defined plugins, one has full control over how events produced by the products (starting or stopping a JCL, QIX transactions, etc.) are handled, what to connect to, etc.
The QIX, IMSql, and Raincode JCL distributions include a plugin that connects to an OpenTelemetry endpoint, which can be easily replaced or extended for more functionality or to connect to an entirely different platform if necessary.
16.2.1. Event Structure
The events produced by all Raincode products follow a consistent naming convention. The event names are made of three parts, separated by colons, according to the following pattern:
-
Product: The name of the product, forced in lower case, e.g. qix or ims
-
Name: The type object the event is about, e.g. transaction or aplitdli
-
Verb: The action that was done on that object, e.g. start, stop, abort
For instance, valid event names include:
-
qix:transaction:start
-
ims:transaction:stop
This simple scheme allows optimal flexibility when filtering events by product, object, action or any combination thereof.
| Event | Arguments | Description |
|---|---|---|
ims:transaction:start |
the transaction code |
Start of an IMS transaction |
ims:transaction:stop |
the transaction code |
End of an IMS transaction |
ims:appltdli:start |
the function |
Start of a IMS call (EXEC DLI, CBLTDLI, PLITDLI, CEETDLI, ASMTDLI) using a DB PCB |
ims:appltdli:stop |
the function |
End of a IMS call (EXEC DLI, CBLTDLI, PLITDLI, CEETDLI, ASMTDLI) using a DB PCB |
ims:appltdli_io:start |
the function |
Start of a IMS call (EXEC DLI, CBLTDLI, PLITDLI, CEETDLI, ASMTDLI) using a IO PCB |
ims:appltdli_io:stop |
the function |
End of a IMS call (EXEC DLI, CBLTDLI, PLITDLI, CEETDLI, ASMTDLI) using a IO PCB |
ims:appltdli_alt:start |
the function |
Start of a IMS call (EXEC DLI, CBLTDLI, PLITDLI, CEETDLI, ASMTDLI) using a alternate PCB |
ims:appltdli_alt:stop |
the function |
End of a IMS call (EXEC DLI, CBLTDLI, PLITDLI, CEETDLI, ASMTDLI) using a alternate PCB |
qix:transaction:start |
the transaction code |
Start of on CICS transaction |
qix:transaction:stop |
the transaction code |
End of on CICS transaction |
batch:job:preexecute |
the name of the job |
Start of a job (JCL) |
batch:job:postexecute |
the name of the job |
End of a job (JCL) |
batch:step:preexecute |
the name of the step |
Start of a step |
batch:step:postexecute |
the name of the step |
End of a step |
16.2.2. The Telemetry plugin
The plugin provides a single interface for events behind which the user can customize the filtering and connection to the telemetry API of choice. This interface is made using a single method.
LogTelemetryEvent(name, args…)
To which the first parameter will always be the event name, and the following parameters will depend on the event itself.
LogTelemetryEvent("qix:transaction:start", Transaction.ID);
LogTelemetryEvent("qix:transaction:stop", Transaction.ID, transactionResult.Error);
If only a subset of the events must be reacted to, one can use an appropriate filtering regular expression, taking advantage of the naming convention described above.
public void LogTelemetryEvent(string eventName, params string[] eventData){
switch (eventName)
{
case "ims:transaction:start":
StartIMSqlTransactionTelemetry(eventData[0]);
break;
case "ims:transaction:stop":
StopIMSqlTransactionTelemetry(eventData[0], eventData[1]);
break;
case "ims:appltdli:start":
StartAppltdliTelemetry(eventData[0]);
break;
case "ims:appltdli:stop":
StopAppltdliTelemetry(eventData[0]);
break;
default:
break;
}
}
| The sample telemetry plugin can be found at %RCDIR%\plugins\AppInsights. |
16.2.3. Using a plugin: command line
Providing the telemetry plugin follows the same options as providing any plugin to an application.
Use -Plugin to provide a path to an assembly.
Submit.exe -Plugin=<path to assembly>
Or you can use -PluginPath to provide a path to a folder where all the assemblies will be scanned for plugins.
Submit.exe -PluginPath=<path to folder>
The screenshot below was captured by connecting Raincode JCL to .NET Aspire® and using Application Insight for visualization.
17. Raincode dual SQL runtime- Introduction
This document describes how to use the Raincode dual SQL runtime (also known as RainCodeLegacySqlDB2OleDbSqlServer) across multiple Raincode products. The dual SQL runtime targets both SQL Server and Db2, using the Microsoft OLE DB Provider for DB2. It can leverage Microsoft Distributed Transaction Coordinator (MSDTC, or DTC) to allow distributing the transaction and guarantee transactional integrity between SQL Server and Db2.
17.1. Prerequisites
-
SQL Server
-
Db2
-
Raincode Stack
-
Microsoft OLE DB Provider for DB2
-
Create packages in Db2 using Data Access Tool (when using DTC)
-
17.2. RainCodeLegacySqlDB2OleDbSqlServer
This is an SQL runtime implementation compatible with the Raincode Stack suite. It is designed to enable connections to both SQL Server and Db2, allowing a single COBOL program to work with both databases in the same execution.
| It is not a generic SQL runtime that can be used to target any SQL database; it is confined to targeting SQL Server and Db2. |
The rest of this section will explain how RainCodeLegacySqlDB2OleDbSqlServer works. Later sections will explain how to configure and use it in the Raincode product suite with the help of samples.
SQL Server is the main database, and when the program starts, a connection is opened using the connection string specified in the configuration file (see Configuration file). All EXEC SQL statements will be run against SQL Server until it encounters an EXEC SQL CONNECT TO statement.
When an EXEC SQL CONNECT TO statement is executed, RainCodeLegacySqlDB2OleDbSqlServer establishes a connection to Db2 using the name specified in the CONNECT TO statement (see the Configuration file for details on how to configure this). Once the connection is established, all subsequent EXEC SQL statements will be executed against Db2, until a new CONNECT TO, SET CONNECTION or CONNECT RESET command is issued.
SET CONNECTION will switch to a previously opened Db2 connection.
CONNECT RESET will set the Db2 connection aside (not closed), and all subsequent SQL queries will be run against SQL Server. Calling CONNECT RESET always causes RainCodeLegacySqlDB2OleDbSqlServer to switch back to using the SQL Server connection.
17.3. Instantiating RainCodeLegacySqlDB2OleDbSqlServer
The RainCodeLegacySqlDB2OleDbSqlServer requires two or more connection strings: one for SQL Server and one or more for Db2. To achieve this, RainCodeLegacySqlDB2OleDbSqlServer requires a configuration file providing, among other things, the necessary connection strings.
In the Raincode Stack suite, wherever a connection string can be specified, and when using RainCodeLegacySqlDB2OleDbSqlServer, the path to the configuration file should be specified instead. For instance, in Raincode JCL, RcDbConnections.csv should have a plan specifying RainCodeLegacySqlDB2OleDbSqlServer as the SQL target, and instead of a connection string, the path to a configuration file, like so:
DUALPLAN,RainCodeLegacySqlDB2OleDbSqlServer,DualRuntimeConfig.cfg
17.3.1. Configuration file
| The format of this file is subject to change in the future. |
The configuration is an XML file defining the following attributes:
-
SqlServerConnectionString: A mandatory connection string for SQL Server.
-
XXXX_ConnectionString: An optional connection string for Db2. Replace XXXX with the name passed to the
CONNECT TOin the COBOL program. You can specify multiple such connection strings, one for each Db2 instance that the program can connect to. -
UseDTC: An optional boolean flag specifying whether the dual runtime should use DTC (Distributed Transaction Coordinator).
Valid values are
trueandfalse(case insensitive). The default value isfalse.In practice, this suppresses any ambient transaction by instantiating a
TransactionScopewith optionTransactionScopeOption.Suppress. Commits and rollbacks are handled separately for each database used.When UseDTC="true", make sure to specifyUnits of Work=DUW;AutoCommit=False;in the OLE DB for Db2 connection string, otherwise the distributed transaction will fail with exceptionSystem.InvalidOperationException: The ITransactionLocal interface is not supported by the 'DB2OLEDB' provider. Local transactions are unavailable with the current provider.when enlisting the Db2 connection into the current transaction.When UseDTC="false", make sure to specifyUnits of Work=RUW;AutoCommit=False;in the OLE DB for Db2 connection string, otherwise you’ll get exceptionSystem.InvalidOperationException: The ITransactionLocal interface is not supported by the 'DB2OLEDB' provider. Local transactions are unavailable with the current provider.when querying Db2 for the first time.
17.3.2. Samples
Three sample examples are provided to illustrate how the dual runtime integrates with the different Raincode products:
-
Raincode JCL
-
Raincode QIX
-
Raincode Stored Procedure Runner
These can be found in %RCDIR%\samples\Dual SQL runtime
Sample batch job: batch sample
This sample shows how to run a batch job with the dual SQL runtime. It consists of a single COBOL program that showcases the dual SQL runtime and distributed transactions.
Description of files
-
dual.jcl: A JCL script used to execute a batch job. It starts the program
DUALCOBusing the planDUALPLAN.//SIMPLE JOB CLASS=A,MSGCLASS=C //STEP0 EXEC PGM=IKJEFT01 //SYSTSIN DD * RUN PROGRAM(DUALCOB) PLAN(DUALPLAN) END /*
-
RcDbConnections.csv: A database connections file mapping
DUALPLANto theRainCodeLegacySqlDB2OleDbSqlServerand the configuration file for said runtime.DUALPLAN,RainCodeLegacySqlDB2OleDbSqlServer,DualRuntimeConfig.cfg
-
DualRuntimeConfig.cfg: An XML configuration file, specific to
DualRuntimeConfig.cfg. It’s contains all necessary connection strings to be used by the dual SQL runtime.<RainCodeLegacySqlDDB2OleDbSqlServer SqlServerConnectionString="..." DB2SRV_ConnectionString="..." />
-
DUALCOB.cob: A COBOL program that connects to Db2 and performs the following SQL queries (not necessarily in this order):
-
SELECT on SQL Server
-
SELECT on Db2
-
INSERT on Db2
-
CONNECT TO
-
SET CONNECTION
-
CONNECT RESET
-
-
sqlserver.ddl and db2.ddl: the DDLs for creating the tables used in
DUALCOB.COB.
Running the sample
-
Update the connection strings in DualRuntimeConfig.cfg
-
Create the required tables in SQL Server and Db2 using the provided DDL files
-
Compile the program by running ./compile.ps1
-
Execute the program with ./run.ps1
After the run completes, you should see the following in the log output:
BEGIN SQL Server SELECT: SQLCODE: 0000000000 WS-C2: initial sql server data -------------- Connect to 'DB2SRV ': SQLCODE: 0000000000 -------------- DB2 Init data SQLCODE: 0000000000 -------------- DB2 SELECT: SQLCODE: 0000000000 C1: initial db2 data -------------- DB2 INSERT: SQLCODE: 0000000000 -------------- DB2 SELECT: SQLCODE: 0000000000 C1: John Dough -------------- SQLCODE: 0000000000 SQL Server SELECT: SQLCODE: 0000000000 WS-C2: initial sql server data -------------- SET CONNECTION: SQLCODE: 0000000000 -------------- DB2 INSERT: SQLCODE: 0000000000 -------------- DB2 SELECT: SQLCODE: 0000000000 C1: John Dough -------------- END
Sample QIX transaction: qix sample
This sample shows how to run a Raincode QIX transaction, running a COBOL program showcasing the dual SQL runtime and distributed transaction.
Description of files
-
createregion.ps1: Edits the file to add connection strings and run to create the QIX region
-
buildbms.ps1: PowerShell script to compile the screen
-
MMENU.bms: the map used by the transaction
-
compile.ps1: PowerShell script to compile the COBOL program
-
DualRuntimeConfig.cfg: configuration file for the
RainCodeLegacySqlDB2OleDbSqlServerSQL runtime. It’s an XML file containing all necessary connection strings to be used by the dual SQL runtime.<RainCodeLegacySqlDDB2OleDbSqlServer SqlServerConnectionString="..." DB2SRV_ConnectionString="..." />
-
DUALCOBQIX.cob: A COBOL program that connects to Db2 and performs the following SQL queries (not necessarily in this order):
-
SELECT on SQL Server
-
SELECT on Db2
-
INSERT on Db2
-
CONNECT TO
-
SET CONNECTION
-
CONNECT RESET
-
-
sqlserver.ddl and db2.ddl: the DDLs for creating the tables used in
DUALCOB.COB. -
startqix.ps1: PowerShell script to start the Raincode QIX region
Running the sample
-
Update the application connection strings in DualRuntimeConfig.cfg.
-
Update the QIX connection string in createregion.ps1 and startqix.ps1.
-
Create the required tables in SQL Server and Db2 using the provided DDL files.
-
Compile the map with buildbms.ps1
-
Compile the program with compile.ps1
-
Run startqix.ps1
-
In a 3270 terminal emulator, connect to the QIX terminal server.
After the run completes, you should see the following on the terminal emulator:
MYTR CUSTOMER CATALOG Raincode TERMID: DEMO 08:46 SQL Server SELECT: SQLCODE = 00000000, C2 = initial sql server data Connect to: DB2SRV , SQLCODE = 00000000 DB2 Init data (DELETE): SQLCODE = 00000000 DB2 Init data (INSERT): SQLCODE = 00000000 DB2 SELECT: SQLCODE = 00000000, C1 = initial db2 data DB2 INSERT: SQLCODE = 00000000 DB2 SELECT: SQLCODE = 00000000, C1 = John Dough CONNECT RESET SQLCODE = 00000000 SQL Server SELECT: SQLCODE = 00000000, C2 = initial sql server data SET CONNECTION: SQLCODE = 00000000 DB2 INSERT: SQLCODE = 00000000 F3: Exit ENTER: Process
Sample COBOL stored procedure: sp sample
This sample shows how to run a COBOL stored procedure using the dual SQL runtime, in the context of the Raincode Stored Procedure Runner.
Description of files
-
compile.ps1: A PowerShell script to compile the COBOL program and generate the C# helper program.
-
config.xml: An XML configuration file for the Raincode Stored Procedure Runner. In the context of using the dual sql runtime, the most important lines are these:
SqlRuntime="RainCodeLegacySqlDB2OleDbSqlServer" SqlRuntimeConnectionString="path_to_DualRuntimeConfig.cfg"
The other attributes
ProgramsPath,HelpersPathshould be filled according to Raincode Stored Procedure Runner Configuration file -
DualRuntimeConfig.cfg: configuration file for the
RainCodeLegacySqlDB2OleDbSqlServerSQL runtime. It’s an XML file containing all necessary connection strings to be used by the dual SQL runtime. In the context of running a COBOL stored procedure, theUseDTCattribute is set to false.<RainCodeLegacySqlDDB2OleDbSqlServer SqlServerConnectionString="..." DB2SRV_ConnectionString="..." UseDTC="false" />
-
DUALCOBSP.cob: A COBOL program that connects to Db2 and performs the following SQL queries (not necessarily in this order):
-
SELECT on SQL Server
-
SELECT on Db2
-
INSERT on Db2
-
CONNECT TO
-
SET CONNECTION
-
CONNECT RESET
-
-
sqlserver.ddl and db2.ddl: the DDLs for creating the tables used in
DUALCOB.COB -
startqix.ps1: A PowerShell script to start the Raincode QIX region
Running the sample
Run compile.ps1 to generate the helper program and the .dll file of the COBOL program. Then, follow instructions at Deploying a COBOL stored procedure to deploy the COBOL stored procedure.
Specifically, udpate $env:RCDIR\StoredProcedureRunner\config.xml with appropriate values, using the config.xml included in this sample as reference.
The COBOL stored procedure can be tested by running the following T-SQL script in SQL Server Management Studio, for example.
DECLARE @return_value int EXEC @return_value = [dbo].[DUALCOBSP] @P0 = 42 SELECT 'Return Value' = @return_value GO
After the successful execution, you should see the following output in the Messages tab:
BEGIN2 P1: 000000042 SQL Server SELECT: SQLCODE: 0000000000 WS-C2: initial sql server data -------------- Connect to 'DB2SRV ': SQLCODE: 0000000000 -------------- DB2 SELECT: SQLCODE: 0000000000 C1: John Dough -------------- DB2 INSERT: SQLCODE: 0000000000 --------- STDOUT message(s) from external script: ----- DB2 SELECT: SQLCODE: 0000000000 C1: John Dough -------------- SQLCODE: 0000000000 SQL Server SELECT: SQLCODE: 0000000000 WS-C2: initial sql server data -------------- SET CONNECTION: SQLCODE: 0000000000 -------------- DB2 INSERT: SQLCODE: 0000000000 -------------- DB2 SELECT: SQLCODE: 0000000000 C1: John Dough -------------- END
17.4. Troubleshooting
17.4.1. System.InvalidOperationException: The 'DB2OLEDB' provider is not registered on the local machine.
Cause: The Microsoft OLE DB Provider for Db2 is not installed.
Fix: install Microsoft OLE DB Provider for Db2
17.4.2. System.Transactions.TransactionManagerCommunicationException: Network access for Distributed Transaction Manager (MSDTC) has been disabled.
Cause: MSDTC network access is disabled.
Fix: Enable MSDTC network access in Component Services
17.4.3. Error: MSDTC was unable to read its configuration information. (0x8004D027)
Cause: when running a COBOL stored procedure with the dual sql runtime, the Db2 connection is enlisted in the TransactionScope, causing MSDTC to kick in. MSDTC does not work in SQL Server Language Extensions (the environment used to run a COBOL stored procedure).
Fix: Disable DTC by specifying xml attribute UseDTC="false" in the configuration file.
17.4.4. System.InvalidOperationException: The ITransactionLocal interface is not supported by the 'DB2OLEDB' provider. Local transactions are unavailable with the current provider.
Cause: There’s a mismatch in the configuration file.
Fix:
-
When DTC is used, make sure you specify
Units of Work=DUWin the Db2 connection string. -
Without DTC, make sure you specify
Units of Work=RUWin the Db2 connection string.
Appendix A: The repository
This section overviews the Raincode legacy compilers, Raincode IMSql and Raincode JCL JOB repository. The repository contains detailed information on the tables gathered by the legacy compilers, IMSql and JCL JOBs. The repository is structured into several SQL tables and stored in a SQLite database (.DB3 file).
The repository can be explored using DB Browser for SQLite®, which lets you see the database structure, browse data, execute SQL queries, and provide many more options.
| For the sake of readability of the documentation, this section is repeated identically in the following manuals: Stack, IMSql, and JCL. |
Some actions that can be performed using DB Browser are:
-
Exploring the database structure
For example, as illustrated in the screenshot below, the RC_PROGRAM table contains information about program files that have been analyzed by Raincode legacy compilers.
-
Browsing data
For example, as illustrated in the screenshot below, users can explore the data within the RC_PROGRAM table.
-
Executing SQL queries
For example, users can write queries to investigate the database content. The query in the screenshot below displays a list of programs for which the Raincode compiler reported zero errors.
Raincode also provides a PowerBI template called Raincode Insight, to visualise the repository’s contents.
Below are some screenshots from a sample repository captured using the Raincode Insight tool.
The first screenshot illustrates the Raincode Insight dashboard.
The second screenshot displays the general statistics of the portfolio.
Here are the links to the available Raincode repositories:
A.1. JCL JOB repository
A.1.1. RC_JCL_JOB table
The RC_JCL_JOB table holds information about the submitted JCL job.
| Column | Type | Description |
|---|---|---|
|
Int32 |
The record identifier for JCL job. RC_ID is the key of this record. |
|
String |
Name of submitted JCL job |
|
String |
JCL job path |
|
String |
JCL job conditions. For example:(0,GT) |
|
String |
Time when the job was submitted |
|
String |
Time taken to scan JCL (milliseconds) |
A.1.2. RC_JCL_PGM_STEP table
The RC_JCL_PGM_STEP table holds information about the program steps of submitted jobs.
| Column | Type | Description |
|---|---|---|
|
Int32 |
Foreign key to entry in RC_JCL_JOB. Identifies the program on which these data apply. |
|
Int32 |
The pair of |
|
String |
Name of JCL job step |
|
String |
Name of the program to be executed in JCL step |
|
String |
Program parameters |
|
String |
Program conditions |
|
String |
The utility used to run the program. For example, IKJEFT, DFSRRC00. |
|
String |
Program executable |
A.1.3. RC_JCL_PROC_STEP table
The RC_JCL_PROC_STEP table holds information about the procedure steps of submitted jobs.
| Column | Type | Description |
|---|---|---|
|
Int32 |
Foreign key to entry in RC_JCL_JOB. Identifies the program on which these data apply. |
|
Int32 |
The pair of |
|
String |
Name of JCL job step |
|
String |
Name of the procedure to be executed in JCL step |
|
String |
Procedure parameters |
|
String |
Procedure conditions |
|
String |
Procedure source code |
A.1.4. RC_JCL_DD table
The RC_JCL_DD table holds information about data definitions of submitted jobs.
| Column | Type | Description |
|---|---|---|
|
Int32 |
Foreign key to entry in RC_JCL_JOB. Identifies the program on which these data apply. |
|
Int32 |
The pair of |
|
String |
Data definition name |
|
String |
Dataset name |
|
String |
Data definition disposition |
|
Boolean |
Indication if DD is used as DUMMY dataset |
|
String |
Instream data content |
|
Int32 |
|
|
Int32 |
|
A.1.5. RC_JCL_ERR table
The RC_JCL_ERR table holds information about errors of submitted jobs.
| Column | Type | Description |
|---|---|---|
|
Int32 |
Foreign key to entry in RC_JCL_JOB. Identifies the program on which these data apply. |
|
Int32 |
The pair of |
|
String |
JCL error type |
|
String |
Error message including the cause of an error |
|
Int32 |
The line number where the error occurs |
A.1.6. RC_JCL_VAR table
The RC_JCL_VAR table holds information about the variables used in the submitted jobs.
| Column | Type | Description |
|---|---|---|
|
Int32 |
Foreign key to entry in RC_JCL_JOB. Identifies the program on which these data apply. |
|
Int32 |
The pair of |
|
String |
The name of the variable |
|
String |
The value of the variable. If the variable is not found, the value is the name of the variable prefixed by v. |
|
Boolean |
This column contains only |
|
Boolean |
|
A.1.7. RC_UTILITIES_PARSING_STATUS table
The RC_UTILITIES_PARSING_STATUS table holds information about the SYSIN parsing done by the utilities (SORT, IKJEFT, …).
| Column | Type | Description |
|---|---|---|
|
Int32 |
Foreign key to entry in RC_JCL_JOB. Identifies the program on which these data apply. |
|
Int32 |
The pair of |
|
String |
The name of the step |
|
String |
The name of the utility |
|
String |
The command sent to the utility (usually the SYSIN) |
|
String |
The error message, if any |
|
Int32 |
The column number where the error occurs |
|
Boolean |
Returns |