IBM i e-Book
A Developer’s Guide to Mastering IBM i Concepts
IBM i Index
IBM i History and Overview
System Architecture
Development Tools
Deep Dive into DDS and DDL
Control Language (CL)
Report Program Generator (RPG)
Integrated Language Environment
SQL on IBM i
Jobs & Logs
RPG Built in Functions
- Char
- Check
- Date
- Diff
- Div
- Elem
- Eof
- Error
- Found
- List
- Lower
- Max
- Minutes
- Months
- Occur
- Open
- Parms
- Range
- Rem
- Scanrpl
- Sqrt
- Abs
- Checkr
- Days
- Dec
- Decpos
- Editc
- Equal
- Hours
- Inth
- Len
- Lookup
- Maxarr
- Min
- Minarr
- Replace
- Scan
- Scanr
- Seconds
- Size
- Split
- Status
- Subdt
- Subst
- Timestamp
- Trim
- Triml
- Trimr
- Uns
- Upper
- Xfoot
- Xlate
- Years
RPGLE Opcodes
- Z-add(H)
- Unlock
- Scan(E)
- Readpe
- Read
- Open
- Mult & Mult(H)
- Monitor
- Lookup
- LeaveSr
- Leave
- Exsr
- Do
- Cat
- Callp
- Callb
- Call
- BegSr
- Z-sub(H)
- Time
- Z-sub
- Z-add
- Xlate(E P)
- Xlate
- Xfoot
- Write
- When
- Update
- Subst(E P)
- Subdur
- Sorta
- Seton
- Setoff
- Setll
- Setgt
- Select
- Return
- Readp
- Reade
- Plist
- Parm
- Other
- Opcode Extender for File Operations
- On-Error
- Occur
- Mvr
- Movel
- Klist
- Kfld
- Iter
- In & Out
- IfXX
- If
- For
- Extrct
- Exfmt
- Except(Rpgle)/Excpt(Rpg)
- Eval(R)
- Eval (M)
- Eval
- Dump(A)
- Dsply
- DoW
- DoU
- Div
- Delete
- Define
- Comp
- Close
- Check(E)
- Chain
- Cat(P)
- Adddur
- Add(H)
- Add
Control Language (CL)
Operations and Functions
Built In Functions
Introduction:
Built-in function is a function that is already available in a programming language, application, or another tool that can be accessed by end users. The term “built-in” refers to the fact that these functions are part of the core functionality of the language. A variety of different office suites, business applications, and programming languages offer built-in functions to simplify the user experience. The following is a list of built-in functions that can be utilized in CL:
- %ADDRESS
Syntax ->%ADDRESS(variable name) / %ADDR(variable name)
- %BINARY
Syntax ->%BINARY(character-variable-name starting-position length)
- %CHECK
Syntax ->%CHECK(comparator-string base-string [starting-position])
- %CHECKR
Syntax ->%CHECKR(comparator-string base-string [starting-position])
- %OFFSET
Syntax ->%OFFSET(variable name)/ %OFS(variable name)
- %SCAN
Syntax ->%SCAN(search-argument source-string [starting-position])
- %SUBSTRING
Syntax ->%SUBSTRING(character-variable-name starting-position length)/
%SST(character-variable-name starting-position length)
- %SWITCH
Syntax ->%SWITCH(8-character-mask)
- %TRIM
Syntax ->%TRIM(character-variable-name [characters-to-trim])
- %TRIML
Syntax ->%TRIML(character-variable-name [characters-to-trim])
- %TRIMR
Syntax ->%TRIMR(character-variable-name [characters-to-trim])
- %CHAR
Syntax ->%CHAR(convert-argument)
- %DEC
Syntax ->%DEC(convert-argument [total-digits decimal-places])
- %INT
Syntax ->%INT(convert-argument)
- %LEN
Syntax ->%LEN(variable-argument)
- %LOWER
Syntax ->%LOWER(input-string [CCSID])
- %UPPER
Syntax ->%UPPER(input-string [CCSID])
- %PARMS
Syntax ->%PARMS()
- %SIZE
Syntax ->%SIZE(variable-argument)
- %UINT
Syntax ->%UINT(convert-argument) / %UNS(convert-argument)
Operators In CL
Introduction:
It is a symbol that usually represents an action or process. These symbols were adapted from mathematics and logic. An operator can manipulate a certain value or operand. For example, in 2 + 3, the 2 and 3 are the operands and + symbol is operator. Below is the list of common operators that can be utilized in CL:
Predefined value | Predefined symbol | Meaning | Type |
---|---|---|---|
+ | Addition | Arithmetic operator | |
– | Subtraction | Arithmetic operator | |
* | Multiplication | Arithmetic operator | |
/ | Division | Arithmetic operator | |
*CAT | || | Concatenation | Character string operator |
*BCAT | |> | Blank insertion with concatenation | Character string operator |
*TCAT | |< | Blank truncation with concatenation | Character string operator |
*AND | & | AND | Logical operator |
*OR | | | OR | Logical operator |
*NOT | ¬ | NOT | Logical operator |
*EQ | = | Equal | Relational operator |
*GT | > | Greater than | Relational operator |
*LT | < | Less than | Relational operator |
*GE | >= | Greater than or equal | Relational operator |
*LE | <= | Less than or equal | Relational operator |
*NE | ¬= | Not equal | Relational operator |
*NG | ¬> | Not greater than | Relational operator |
*NL | ¬< | Not less than | Relational operator |
File Operations
- Databases files
- Display files
We can send a display to a workstation and receive input from the workstation for use in the CL procedure or program, or we can read data from a database file for use in the CL procedure or program.
There are few important points related to variables used in CL:
1. | Datatypes used for CL variables are *CHAR,*DEC,*LGL,*INT,*UINT. |
2. | Variable names start with ‘&’, for example. &IN03, &Count etc. |
3. | DCL command is used to declare the variables. |
4. | Variables from display file will automatically be available to program. |
5. | CHGVAR command is used to assign values to the variables, for example, CHGVAR VAR(&Count) Value (2). |
There are some limitations in CL compared to RPGLE:
CL | RPGLE |
---|---|
1.It cannot be used to ADD or UPDATE database files, as it does not have WRITE or UPDATE opcodes like RPGLE. However, we can use RUNSQL command to perform these operations. | 1. It can be used to ADD or Update Database files. |
2. It does not support subfiles. But it does support one output message subfile. | 2. It support all types of subfiles. |
3.It does not support program described files. | 3. It does support program described files. |
4. It does not support printer files. | 4. It does support printer files. |
5. It does not support Indicator data structure. | 5. It does support indicator data structure. |
6. It can have only five files(Database and display files) per program. | 5. It can have maximum 50 files (Including 8 printer files). |
There are few important points related to usage of database files and display files in CL programs:
Database File | Display File |
---|---|
1. Only database files with a single record format may be used by a CL procedure or program. | 1. Display files may have up to 99 record formats. |
2. The files may be either physical or logical files, and a logical file may be defined over multiple physical file members. | 2. The file defined must be display file. |
3. Only input operations, with the RCVF command, are allowed. | 3. All data manipulation commands (SNDF, SNDRCVF, RCVF, ENDRCV and WAIT) are allowed for display files. |
4. DDS is not required to create a physical file which is referred to in a CL procedure or program. If DDS is not used to create a physical file, the file has a record format with the same name as the file, and there is one field in the record format with the same name as the file, and with the same length as the record length of the file (RCDLEN parameter of the CRTPF command). | 4. The display file must be defined with the DDS. |
5. The file need not have a member when it is created for the module or program. It must, however, have a member when the file is processed by the program. | 5.The display file must have a member when it is created for the module or program. |
6.The file is opened for input only when the first Receive File (RCVF) command is processed. The file must exist and have a member at that time. | 6. The display file is opened for both input and output when the first SNDF, SNDRCVF, or RCVF command is processed. |
7. The file remains open until the procedure or original program model (OPM) program returns or when the end of file is reached. When the end of file is reached, message CPF0864 is sent to the CL procedure or program, and additional operations are not allowed for the file. The procedure or program should monitor this message and take appropriate action when end of file is reached. | 7. The file remains open until the procedure or OPM program returns. |
In this, we will describe all the operations which we can perform on databases file. The operations include read, write, update, chain, set lower limit, these operations are equivalent to the RPG files operation and here we will see how we can implement these in CL programs.
We will also describe all the operations which we can perform on display files. We have also listed all the commands which we can use to handle the files in CL programs.
This will also include all the operations or commands related to file operation which are not supported by the CL program or procedure.
Usage:
The operations which we can perform on files:
Databases files:
In CL only input operation can be done on database files using RCVF command. The other operations like write or update on database files cannot be done in CL.
But in the below examples we will see how we can use alternative ways to perform operations like write, set lower limit, chain , update which we are doing in RPG same we can do in CL.
1)Read Operation.
To be able to read a file in a CL program,
- First, we must Declare the File using declare file command, DCLF. The file must exist before compilation of the CL program.
- Then use the Receive File command, RCVF to read or retrieve data from the file.
1.1) If we want to read the file in loop then, we can use DO loop:
- We have declared the file STUMASTER which we want to read.
- We are using Do loop to read the file, so it will read the file from the start.
- The MONMSG Message ID CPF0864 will tell the end of file is reached and then EXEC command will execute; and it will leave the loop.
1.2) Using Labels:
We have seen above that we have used Do loop for reading the file in loop. Alternative to loops, in CL we can use labels. We use GOTO command to move to the labels.
The below example shows how we can use labels for reading a file till the end of file is reached.
- READ and END are the labels.
- On line 4.01, it will read the record from file.
- On line 4.02, if we reach the end of file then Exec command execute, and it will send the program to the label END.
- On line 4.03, if we don’t reach the end of file then it will send the program to label READ to execute the RCVF command again.
1.3) If we want to read more than one file:
We need to use the Open File Identifier, OPNID, parameter to give each file its own unique id. We just use a letter, but the OPNID can be up to ten characters.
- When we use the RCVF we need to mention which file to use. The OPNID is used and must match the value in a file declaration.
- When we use the OPNID the fields’ name are automatically prefixed with the open identifier and an underscore (_). This ensures that the field names are unique.
We use PREFIX keyword in RPG, for that operation in CL we can use OPNID which will make each field names unique.
1.4) If we want to read a file from a particular record not from start:
This is like what we are doing in RPGLE like SETLL, CHAIN but in CL we don’t have these commands.
But for this we can use Override Database File command, OVRDBF.
In the below example we will see how we can do this,
- First, we have declared a database file.
- We assigned the value to variable &key on which we want to position the pointer.
- Then, we have used the OVRDBF command for overriding the declared file (STUMASTER) using the Starting Position in File parameter; POSITION will position the file pointer to that point in the file when we perform our first “read”. The four parts of this parameter are:
- Retrieve order – *KEY this means position the file pointer to the exact match on the key. The other options we can use are *KEYB, *KEYBE, *KEYA, *KEYAE, *RRN.
- Number of key fields – The file which we are reading that file has how many key fields. This file has two key fields.
- Record format with the key – by using *N we are telling the command to use the only member in the file.
- Key value – this can either be a variable, as we have shown, or we can enter a literal instead.
After positing the pointer at a specific record, we are reading file in a loop.
Note: OVRDBF is used to override the attribute of a physical file. This can make our program to use some other file for the one named to be used in the program.
All overrides are temporary and are effective until where the override command has been in scope.
The parameters of OVRDBF used in below example are;
- File: specify the file being declared in the program.
- Position: It tells the starting position for reading records from the database file. Possible values are *NONE, *START, *END, *RRN (provide relative record number i.e. nth record in file), record specified on key field value (*KEY, *KEYA, *KEYAE, *KEYB, *KEYBE).
- Ovrscope: It tells the scope of the override. There can be three possible values it can have:
- *ACTGRPDFN: The scope of the override is determined by the activation group of the program that calls this command. when default activation group then scope would be call level of calling program otherwise activation group of the calling program.
- *CALLLVL: The scope of the override is determined by the current call level. All open operations done at higher or same call level than the current call level are affected by this override.
- *JOB:The scope of the override is the job in which the override occurs.
2)Write Operation
In CL there is no write command. But we can use Run SQL Command to insert a record into a file.
In the below example we have used SQL query and run it using run SQL command to insert the data into file. In the below example we want to insert values in two fields so for that we have declared two variables &VAR1 and &VAR2 with values. These variables are used in SQL statement to insert value into table.
3) Update Operation:
CL does not have an Update command, so in CL we cannot update database files.
But for this, below we have shown an alternative way to update database files and for that we can use RUNSQL command.
Let’s discuss what we are doing:
- First, we have declared a file which we want to update.
- We have assigned the value in the variable (&Key), this we will use to update the record which matches this value.
- We are positioning the pointer to the &key value in the database file and for this we are overriding the declared file (STUMASTER) using the Starting Position In File parameter, POSITION, this will position the file pointer to that point in the file where we perform our “UPDATE”.
- After positioning at specific record, we can use RUNSQL command to update the record. Inside the RUNSQL command we can put the update SQL query.
4) Error handling for file operation in CL:
When RCVF command is used to read the declared file in CL, and if the file is empty or the end of file is reached it will throw a error if it is not handled.
First, we will see if we do not handle error then what happens.
Below is an example of the error.
- We are reading the file STUMASTER which is empty.
In the code below we are reading the file which is empty using RCVF command.
In the above example, if the file has some data , even then it will throw error when end of file is reached and we have not handled the end of file condition.
To handle the above errors we use MONMSG.
Now in the code,
- On line 4.02 we have defined the MONMSG with MSGID CPF0864 which tells the end of file is reached or file is empty and the EXEC command executed and it send the program to Endpgm and program ended normally.
To handle any error that occurred in a program we can define one MONMSG and it will handle at the program level.
Below is the example for that.
- On Line 2.05 we have defined MONMSG with MSGID CPF0000 which is generic message id and it will handle error at program level means any error occur in program it will handle.
- On Line 4.03 we have used SNDPGMMSG to send a message that error is occurred.
When we call the above code then, we got the message like below
5) Using Commit & Rollback in CL:
Commit means that the changes made in the current transaction are made permanent and Rollback means cancelling all the transactions made in the current transaction. With the help of these commands we can maintain the consistency in the data of files.
To use commit on a file the file must be journaled.
The commit and rollback is used in a block, which starts with a command STRCMTCTL (Start Commitment Control) and end by a command ENDCMTCTL ( End Commitment control) . Inside these we will perform the operation on file and use the commit or rollback as per requirement.
Let’s see how we can use commit and rollback in CL by a simple example-
In the below code we will first update the file STUMASTER, then we use commit to permanent the changes then we again update the file STUMASTER, then we use rollback to cancel the changes in the file.
Explanation:
- On Line 2.04, file STUMASTER is declared.
- On Line 2.08, STRCMTCTL is used with LCKLVL as *CHG which means any change in the file, and this will start the commitment control block.
- On Line 2.10, we position the pointer on the file equal to the key value.
- On line 2.12, we are reading the file using RCVF.
- On line 2.14, we are updating the value of field Class in file with 5 where Field Name = ‘CNTRL’.
- On line 2.20, we used Commit which makes the changes in the file permanent.
- On Line 2.21, we update the Field Class by 7 in file.
- On line 2.25, we used Rollback which means it will cancel the changes done in file just now.
After ROLLBACK, because of Rollback the update of Field ‘CLASS’ to 7 is cancelled and it will update by previous value.
On line 2.27 ENDCMTCTL (End Commitment Control) is used which end the commitment control block.
B).Display files:
Now let’s see how we can use display files in CL. For the display files three commands are basically used DCLF, SNDF, SNDRCVF. The SNDRCVF is like what we have in the RPGLE as EXFMT. Let’s see how we can use display files in CL using an example shown below.
The DDS of the display file named AIRTHDSP where we are finding the position of character from the entered string.
Now the program using above display file is:
In the program we can see,
- First using DCLF command we have declared the display file AIRTHDSP.
- Then we have used SNDRCVF which is used to receive and send data to display screen, so basically it will show the display screen.
- Then we have put the logic to perform the operation which we want to perform on display file.
Let’s see the result of the above example.
In the entered string we have to find the position of $ which is 26.
Commands that are used in CL for file handling:
1.DCLF : This command is used to declare a display or database file to your CL procedure or program. The Declare File (DCLF) command cannot be used to declare files such as tape, printer, and mixed files.
The file must exist before the module or program is compiled.
2. The only commands we can use with a display file to send or receive data in CL procedures and programs are the Send File (SNDF), Receive File (RCVF), and Send/Receive File (SNDRCVF) commands.
2.1.SNDF : The Send File (SNDF) command is used by a CL program or ILE CL procedure to send a record to a display device that is being used by an interactive user.
- This command is valid only within a CL program or ILE CL procedure.
- This command is valid only for display files.
- This command cannot be used with database files.
2.2.RCVF : The Receive File (RCVF) command is used by a CL program or ILE CL procedure to receive data from a display device or database file. The command reads a record from the file and puts the data from the record into one or more CL variables. The data that is entered by a user at the display or is contained in the input record is copied into CL variables in the program by the RCVF command, where it is processed by the program.
If the file has not been opened by a previous RCVF, SNDRCVF, or SNDF command, it is opened by this command. If the file has been previously closed due to an end-of-file condition on a previous RCVF command, an error occurs.
- SNDRCVF : The Send/Receive File (SNDRCVF) command is used by a CL program or ILE CL procedure to send data to and receive data from a device that is being used interactively by a user. If the device file has not been opened, it is opened by this command.
This command is valid only within a CL program or ILE CL procedure and only for display files. It cannot be used with database files.
Restrictions:
There are some restrictions or don’ts for files in CL, and those are listed below:
1. | The WAIT and DEV parameters on the Receive File (RCVF) command are not allowed for database files. In addition, the SNDF, SNDRCVF, and ENDRCV commands are not allowed for database files. |
2. | The CL does not support Indicator data structure, so in display file DDS INDARA keyword should not be used. |
3. | We don’t have write or update commands in CL for add or update of record in databases files, for this we have discussed the alternative above. |
4. | CL does not support subfiles , but a single output message subfile is a special type of subfile that is supported well in CL. |
5. | CL cannot use Program described files. |
6. | CL cannot use Printer files. |
7. | CL can have only five files (display or database file) per program. |
Code Example:
In the below example we will cover both database file and display file, what we have learned above.
In the example,
- First, we have a database file having four fields Enrollnum, Name, Batch, Department.
- What we have to do is first we have to create a display file and from the display file we have to enter the enrollment number for which we want the record, and if enrollment number found in file, then it should show the records related to that enrollment number on the screen.
The below screen shot is the display file DDS.
The below screen shot is the program for the above example.
Let’s discuss the above example code line by line.
- From line 2.01 to 2.05, we have declared the variables required in the code.
- On line 2.10 and 2.11, we have declared the display file and database file and because here two files are declared so we have used OPNID.
- Inside the loop on line 2.15, we have used SNDRCVF to read and write the display screen.
- On Line 2.25, we put a condition that if F3 is on then exit from screen.
- On Line 2.27 to 2.30, we have put a condition that if we have not entered the enrollment number on screen then it throw error.
- On line 2.32, we have assigned the enrollment number to the variable &key which is used to chain this value on database file.
- On line 2.39 to 2.40, we have used OVRDBF command to position the pointer on the record of database file which matches with the &key value.
- On Line 2.42, we have used RCVF to read the matched record from the database file.
- On line 2.43 to 2.46, we have put logic to manage the error.
- On line 2.49 to 2.52, we are assigning the values to the display screen fields from the database file fields. One important thing here is that on each database file fields we have prefixed the OPNID value.
- On line 2.56, we have used RCLRSC which is used to make sure that every thing is closed and override cleared properly.
Now let’s see the output we will get when we run the above example.
Error & Message Handling
These errors can be categorized as program-defined errors and system errors. Program-defined errors are those you anticipate and handle within your CL program, while system errors are unforeseen issues that may require system messages.
To Handle Errors and Messages in IBM i MONMSG and SNDPGMMSG are the basic command available.
The MONMSG command is a fundamental construct for error handling in CL programs. It is used to monitor specific messages and take actions when those messages occur.
In error handling, it is common to display error messages to the user and/or log them for later analysis. You can use the SNDPGMMSG command to send a message to the program message queue or display it on the user’s screen.
The SNDBRKMSG command can be used to send a break message, stopping program execution.
Error and message handling in CL programming are vital for creating robust applications on the IBM i platform. By effectively handling errors and providing informative messages, you can improve the reliability and maintainability of your programs.
In IBM i (formerly AS/400) CL programming, handling errors and messages is a critical part of ensuring the reliability and robustness of your programs. CL (Control Language) is a scripting language used on the IBM i platform to automate tasks and create programs.
MONMSG
In IBM i, the MONMSG (Monitor Message) command is used for error handling. It allows you to monitor for specific messages and take predefined actions when those messages are issued.
Below is an example and syntax with a detailed explanation of how to use MONMSG with an example:
Syntax of the MONMSG Command:
MONMSG MSGID (message-identifier) EXEC (command)
MSGID: This parameter specifies the message identifier you want to monitor for. we can specify a specific message identifier, a generic message identifier (using asterisks), or a message file name.
EXEC: This parameter specifies the command to execute if the monitored message is received. we can execute various commands, including GOTO, SNDPGMMSG or a custom program.
Example:
Let us think we have a CL (Control Language) program that processes files, and we want to handle any potential errors gracefully. we can use MONMSG like this:
PGM
/* Attempt to open a file */
OVRDBF FILE(INPUT) TOFILE(MYLIB/MYFILE) OVRSCOPE(*JOB)
/* Monitor for any file open errors */
MONMSG MSGID(CPF502B) EXEC(DO)
/* Display an error message */
SNDPGMMSG MSG('Error opening file MYLIB/MYFILE') +
MSGTYPE(*ESCAPE)
/* Handle the error, maybe by logging it and ending the program */
/* Add your error-handling logic here */
ENDDO
/* Continue processing if the file was opened successfully */
/* Add your file processing logic here */
/* Close the file */
DLTOVR FILE(INPUT)
ENDPGM
Description of example:
- The program attempts to open a file using the OVRDBF command.
- The MONMSG command is used to monitor for the specific message CPF502B, which is issued when there is an error opening a file. When this message is encountered, the program jumps to the DO block.
- Inside the DO block, an error message is sent using SNDPGMMSG, and we can add our custom error handling logic.
- After handling the error, we can either end the program or continue with additional processing logic.
- This is a basic example of how to use MONMSG for error handling in IBM i. we can customize it based on our specific requirements and the types of messages you want to monitor in your application.
SNDPGMMSG
In IBM i, the SNDPGMMSG command is used to send a program message to a user or message queue. It is commonly used for error handling and reporting. You can find below a detailed explanation of error handling using SNDPGMMSG with an example.
SNDPGMMSG Command Syntax:
SNDPGMMSG MSG(‘Your message text’) TOUSR(UserProfile) MSGTYPE(*DIAG) MSGDTA(‘Message data’)
MSG: Specifies the message text.
TOUSR: Specifies the user profile to send the message to.
MSGTYPE: Specifies the message type. Use *DIAG for diagnostic messages (common for errors).
MSGDTA: Specifies additional message data.
Example of Error Handling using SNDPGMMSG:
Let’s say, we have a CL program that performs some operations and needs to handle errors by sending messages. Here’s an example:
/* Sample CL Program */
/* Declare variables */
DCL VAR(&ERROR) TYPE(*LGL) VALUE(‘0’) /* Initialize error flag to false */
/* Perform some operations */
/* … */
/* Check for an error condition */
IF (&SOME_CONDITION) THEN
CHGVAR VAR(&ERROR) VALUE(‘1’) /* Set error flag to true */
SNDPGMMSG MSG(‘An error occurred’) TOUSR(USER123) MSGTYPE(*DIAG)
GOTO CMDLBL(ERROR_HANDLING)
ENDIF
/* More operations */
/* Error Handling Label */
ERROR_HANDLING:
IF (&ERROR *EQ ‘1’) THEN
SNDPGMMSG MSG(‘Error Handling: Processing stopped due to an error) TOUSR(USER123) MSGTYPE(*DIAG)
ENDPGM /* Terminate the program */
ENDIF
/* Program continues if no error */
ENDPGM /* End of program */
Description of example:
- We declare a variable &ERROR to track whether an error occurred (initially set to ‘0’ for false).
- After performing some operations, we check for a condition (&SOME_CONDITION) that could indicate an error. If the condition is met, we set &ERROR to ‘1’ and send a diagnostic message using SNDPGMMSG.
- We use a label (ERROR_HANDLING) to handle errors. If &ERROR is set to ‘1’, we send an error message and terminate the program.
- If no error occurred, the program continues its execution, and eventually, it ends gracefully.
- This is a simplified example, and in a real-world scenario, you would have more detailed error handling and possibly log messages to a message queue for further analysis. The SNDPGMMSG command is just one part of error handling on IBM I, and you can customize it further based on your specific needs.
Example:
Usages :
Error handling and message handling are essential aspects of CL programming on IBM i for the following reasons:
Program Reliability: Error handling helps ensure the reliability of your CL programs by allowing you to detect and respond to unexpected conditions or errors. This helps prevent program crashes or unexpected behaviour.
User Feedback: Message handling allows you to communicate with users or operators by sending messages. This can be used to provide feedback, instructions, or warnings, making your programs more user-friendly.
Diagnostic Information: Messages often contain diagnostic information that can be valuable for troubleshooting and debugging. When an error occurs, capturing and logging messages can aid in identifying the root cause.
Graceful Program Termination: Proper error handling ensures that a program terminates gracefully, releasing any acquired resources and cleaning up after itself. This is crucial for maintaining system stability.
Conditional Processing: By monitoring specific messages (e.g., CPF messages for errors), you can implement conditional processing in your CL programs. For example, you might want to take different actions depending on the type of error encountered.
Logging and Auditing: You can log messages to keep a record of program activities, errors, or significant events. This log can be useful for auditing and tracking program behaviour over time.
Interaction with Other Programs: CL programs often interact with other programs or processes. Proper error handling ensures that the calling program or process can respond appropriately to errors raised by the called program.
In summary, error handling and message handling in CL programming on IBM i are crucial for ensuring program reliability, providing feedback to users, diagnosing issues, and maintaining overall system stability.
They enable you to create robust and user-friendly applications on this platform.
Restrictions :
Limited Error Information: CL programs primarily handle messages, and the information provided in messages may be limited. To access more detailed error information, you may need to rely on APIs or interact with other system components.
Message Queue Limitations: Messages are typically sent to message queues, and there may be limitations on the number of messages that can be held in a queue. If the queue becomes full, new messages may be lost.
Message IDs: When using the MONMSG command to monitor for specific messages, you need to know the message IDs in advance. If IBM i introduces new message IDs in future releases, your monitoring may need updates.
Resource Locking: Error handling should be cautious when dealing with resource locks, as improper handling can lead to resource contention issues.
Compatibility Considerations :
IBM I Versions: Error handling and message handling techniques in CL programming are generally consistent across different versions of IBM i, but there might be slight variations or enhancements in newer releases. It is a good practice to check the documentation specific to your IBM i version for any updates or changes.
Message Queue Types: IBM i supports different types of message queues, including program message queues and message queues associated with user profiles. The choice of message queue type can impact how messages are handled and accessed.
Message Queues in Subsystems: When working with subsystems, you need to consider how message queues are managed within the subsystem environment. Subsystem configurations can affect how messages are routed and monitored.
User Profile Settings: User profile settings, such as message queue authorities and message queue monitoring settings, can affect the behaviour of error handling and message handling in CL programs.
Library Lists: Ensure that any message files or message descriptions used in your CL programs are accessible through the library list of the job running the program.
Message File Changes: If you update or change message files or message descriptions, be aware of the potential impact on your CL programs that rely on those messages.
Message Text Language: Consider the language settings of message descriptions and message files. Messages may be presented in different languages based on user or system preferences.
It is important to keep these restrictions and compatibility considerations in mind when designing and maintaining error handling and message handling in IBM i CL programs. Staying informed about system updates and best practices is crucial for effective error and message management.
OVRDBF and OPNQRYF
Introduction
In IBM i CL (Control Language) programming, the “override” concept is used in the context of overriding certain system values and commands temporarily.
The format of this command is:
OVRDBF FILE(overridden-file-name) + TOFILE(library name/database file name)+ MBR(member name) + POSITION(file positioning option) + SECURE(secure from previous override) + SHARE(open data path sharing option) + OVERSCOPE(file override scope)
Below are the key points regarding the use of “override” in CL programming on the AS/400 platform:
- Override Commands: CL programs often use the “OVRDBF” (Override with Database File) command to temporarily change the behavior of a database file. This allows you to use a different file or record format within a program without permanently altering the file’s attributes.
- Override Database Files: “OVRDBF” is commonly used to change the file, library, or member used in a program. For example, you can override a file to work with a specific customer’s data within the same program.
- Override Control Language Defaults: The “OVRPRTF” (Override with Printer File) command is used to change the default attributes of printer files, such as page size, character set, and more, for a specific output operation within a CL program.
- Scope: Overrides in CL programming typically have a local scope, meaning they affect only the specific instance of a command or operation within the program. Once the program finishes its execution, these overrides do not persist.
- Temporary Changes: Overrides provide a way to make temporary changes to the behavior of your CL program without altering system-wide settings. This is especially useful when you need to customize program behavior for specific scenarios.
- Nesting Overrides: You can nest overrides within CL programs. For example, you can override a file within a sub-procedure, and the override will be in effect only for the duration of that sub-procedure.
- Resetting Overrides: It’s important to remember that overrides are temporary. To revert to the default settings, you may need to use the “DLTOVR” (Delete Override) command or simply let the program finish its execution.
Syntax is fixed/free.
In IBM i Control Language (CL), you can use both fixed-format and free-format syntax for the `OVRDBF` (Override Database File) command, just like with other CL commands. Below, we will provide examples of the `OVRDBF` command in both fixed and free formats.
Fixed-Format Syntax:
PGM OVRDBF FILE(MYLIB/MYFILE) TOFILE(MYLIB/MYFILE2) MBR(MEMBER2) /* Other CL commands */ DLTOVR FILE(MYLIB/MYFILE) /* Delete the override */ ENDPGM
In fixed-format CL, you typically start each statement at a specific column and follow a specific structure. The `OVRDBF` command starts at column 6, followed by its parameters. Columns 1-5 are reserved for sequence numbers. The `DLTOVR` command is used to delete the override.
Free-Format Syntax:
PGM OVRDBF FILE(MYLIB/MYFILE) TOFILE(MYLIB/MYFILE2) MBR(MEMBER2) /* Other CL commands */ DLTOVR FILE(MYLIB/MYFILE) /* Delete the override */ ENDPGM
In free-format CL, you have more flexibility in terms of layout and indentation. Statements can start at any position within a line, making the code easier to read. The above example accomplishes the same tasks as the fixed-format example but uses a more modern, flexible syntax.
You can choose the format that best suits your coding style and project requirements, but keep in mind that modern IBM i systems generally support free-format CL for increased readability and maintainability.
Usage
A basic example of how to use the `OVRDBF` command to override file attributes in a CL (Control Language) program:
OVRDBF FILE(MYLIB/MYFILE) TOFILE(MYLIB/MYFILE2) MBR(MEMBER2)
In this example, the `OVRDBF` command is used to override the file attributes for `MYLIB/MYFILE`. It specifies that the program should access `MYLIB/MYFILE2` instead of the default file, and it should use `MEMBER2` as the file member.
NOTE: Overriding file attributes should be used with caution, as it can impact the behavior of programs and jobs. It’s important to document and manage these overrides carefully to avoid unexpected issues. Additionally, you need the appropriate authority to perform file overrides on IBM i.
Example:
Here’s a simple example in IBM i CL programming that demonstrates how to use the “OVRDBF” command to temporarily override a database file:
PGM /* Declare variables */ DCLF FILE(MYLIB/CUSTOMER) OPNID(CUSTFILE) /* Declare file */ /* Override the database file to use a different me mber */ OVRDBF FILE(CUSTFILE) TOFILE(MYLIB/CUSTOMER) MBR(NEWMBR) /* Your program logic here */ /* You can now use the CUSTOMER file with the NEWMBR member */ /* Close the overridden file */ CLOF OPNID(CUSTFILE) /* Delete the override */ DLTOVR FILE(CUSTFILE) ENDPGM
In this example:
- We declare a file using the `DCLF` command, specifying the library (MYLIB) and file (CUSTOMER) that we want to work with. We also give it an open identifier (OPNID) of CUSTFILE.
- We use the “OVRDBF” command to override the CUSTOMER file temporarily. We specify that we want to use a different member (NEWMBR) within the same file. This override will only affect the file operations within the program.
- You can perform your program logic using the overridden file. Any database file operations within the program will use the specified member (NEWMBR) instead of the default.
- After you’ve finished using the overridden file, you close it using the `CLOF` command.
- Finally, we delete the override with the `DLTOVR` command, ensuring that the change doesn’t affect subsequent programs or system-wide operations.
This example demonstrates how to temporarily override a database file member within a CL program, allowing you to work with different data within the same file without permanently changing the file’s attributes.
I’ll include another example of a CL program with expected output:
PGM /* Declare variables */ DCLF FILE(MYLIB/CUSTOMER) OPNID(CUSTFILE) /* Declare file */ DCL &CUSTID *CHAR 5 DCL &CUSTNAME *CHAR 30 /* Override the database file to use a different member */ OVRDBF FILE(CUSTFILE) TOFILE(MYLIB/CUSTOMER) MBR(NEWMEMBER) /* Open the overridden file */ OPNDBF FILE(CUSTFILE) /* Read customer data from the overridden file */ RCVF OPNID(CUSTFILE) MONMSG MSGID(CPF0864) EXEC(GOTO EOF) /* Process customer data */ CHGVAR &CUSTID %SST(CUSTREC 1 5) CHGVAR &CUSTNAME %SST(CUSTREC 6 30) SNDPGMMSG MSG('Customer ID: ' || &CUSTID) SNDPGMMSG MSG('Customer Name: ' || &CUSTNAME) GOTO READFILE /* End of file reached */ EOF: /* Close the overridden file */ CLOF OPNID(CUSTFILE) /* Delete the override */ DLTOVR FILE(CUSTFILE) ENDPGM
In this example, we assume a CUSTOMER file in the MYLIB library with a member named NEWMEMBER(member will be created by CRTMBR). This program opens the file, overrides it to use the NEWMEMBER, retrieves and processes customer records, and then closes and deletes the override.
Expected Output:
Customer ID: 00123 Customer Name: Generic Text Customer ID: 00456 Customer Name: Customer01
This example demonstrates the following steps:
- The program declares variables for customer ID and name.
- It uses the “OVRDBF” command to override the CUSTOMER file, specifying the NEWMEMBER as the member to use.
- The program opens the overridden file using “OPNDBF.”
- It enters a loop to read and process customer records until the end of the file is reached.
- Inside the loop, it extracts customer IDs and names from the record and sends them as messages.
- When the end of the file is reached, it closes the file and deletes the override.
This program temporarily overrides the database file, reads data from the specified member, and processes it, producing the expected output.
Open Query File (OPNQRYF)
Introduction
OPNQRYF command opens a database file that satisfies the database query request. It creates a temporary access path (ODP – Open Data Path) & this access path contains the information needed to select, order, group and join the records. Once the access path is created, we can read the record from the file using normal CL commands. The access path is discarded after its use.
ODP – Access path describes the order in which records are to be read. It can be kept on the system permanently (such as physical or logical file) or temporarily (OPNQRYF). OPNQRYF command creates a temporary access path for one time use, and then discarded. The open data path contains the information like file name, format name, current record pointer, record selection information etc.
Parameters of OPNQRYF:
- FILE – It specifies the name of the file to be processed.
- OPTION – It allows to specify various options for how the query should be processed.
- FORMAT – It specifies the record format used for records. We can define which field to include in output.
- QRYSLT – It specifies the selection criteria for the records to be processed.
- KEYFLD – It specifies the fields to be used to key the records.
- IGNDECERR – It specifies whether to ignore decimal errors.
- COMMIT – Specifies whether to commit the changes to the query file after each record is processed.
- OPNSCOPE – Specifies the scope of the query file.
- DUPKEYCHK – Specifies whether to check for duplicate keys in the query file.
- ALWCPYDTA – Specifies whether the database is allowed to copy data when processing query.
- OPTIMIZE – It specifies whether the query is to be optimized. It can also be used to control level of optimization.
Parameters of OPNQRYF command with SQL equivalents:
OPNQRYF parameter | SQL clause equivalent | Example |
---|---|---|
FILE | From | Select * from EMPPF; |
QRYSLT | Where | Select * from EMPPF where field1 =” value”; |
KEYFLD | Order By | Select * from EMPPF Order By field1 ASC; |
MAPFLD | As | Select field1 AS FLD1 from EMPPF; |
JFLD | Join | Select * from EMPPF Inner Join CUSTPF ON EMPPF.field1 = CUSTPF.field2; |
GRPFLD | Group By | Select * from EMPPF Group by Field1; |
Syntax:
OPNQRYF FILE (lib name/file name
Member-name
Record-format-name)
OPTION (open-option)
FORMAT (lib name/database file name
Record-format name)
QRYSLT (query selection)
KEYFLD (field name)
IGNDECERR(*YES/*NO)
COMMIT(*YES/*NO)
OPNSCOPE (*File name/*USR / ALL)
DUPKEYCHK(*YES/NO/SAME/MSG/UNIQUE)
ALWCPYDTA(*YES/NO)
OPTIMIZE(*NO/YES/MIN/MAX)
Example-
In above example:
- ‘File (WELCOME24/EMPPF)’: specifies the file to be query.
- ‘QRYSLT’: defines the query selection criteria.
- ‘FORMAT’: specifies the output format for the result.
- ‘KEYFLD’: key fields for sorting & selecting unique records.
- ‘IGNDECERR’: Ignores decimal data errors during query processing.
- ‘COMMIT’: defines commitment control behaviour.
- ‘OPNSCOPE’: specifies the scope of open query.
- ‘DUPKEYCHK’: Enables or disable duplicate key checking.
- ‘ALWCPYDTA’: Allows or disallows copying data to temporary file.
- ‘OPTIMIZE’: specifies the optimization level for query processing.
- ‘OPTION’: Sets additional processing options.
OVRDBF – Override Database File (OVRDBF) command is used to change the file named in the program, or certain parameters of a file that are used by the program. All overrides (changes) are temporary and are effective until the override command has been in scope.
Parameters of OVRDBF:
- FILE – It include name of the file to be override (change).
- TOFILE – It include the name of the file to be used in place of the override file.
- MBR – it specifies the member used within the file.
- POSITION – It denotes the position of the cursor in override file.
- SHARE – It specifies whether the override file can be shared with other programs.
Note – OVRDBF is only used to share the open data path within the calling program (By specifying SHARE(*YES)). But if we don’t use the OVRDBF command then open data path will not be shared.
Using OVRDBF command.
Without Using OVRDBF Command.
Usage:
It can be used to open a file to a particular set of records as per the query request.
It can be used for Ordering & Grouping the Records.
It is also used for Joining records from multiple records.
Restrictions & Compatibility:
Restrictions-
- Temporary Nature: Open Query File are temporary files, and their data is only available for the duration of session. They are typically cleared when the session is ended, so we need to save or export the data if we want to keep it for future reference.
- Limited Storage: Open Query File are stored in a temporary library, and there is a limit to the amount of data that can be stored in this library. If query generates a large result set, we may encounter storage limitations.
- Read-Only: OPNQRYF is primarily used for reading data. We cannot use it to update, insert, or delete records in a database file.
- Performance: It may not be as efficient as SQL for certain types of queries.
- Complexity: It becomes complex when dealing with multiple file joins, complex conditions it make challenging to write & maintain query.
Compatibility-
- Query Syntax: Compatibility depends on the specific query for which we are trying to execute and whether it uses features that are supported by the system.
- Library and Object Names: Compatibility can be affected by the naming conventions used for libraries and objects in our system.
Examples:
- Basic Query
- Joining Files
- Sorting Results
- Creating a Temporary Result Set
ILE with CL using Procedures
Introduction
In CLLE, subroutines and procedures are essential programming constructs used to organize and modularize code for better maintainability and reusability. Subroutines and procedures in CLLE provide a way to organize code, promote code reuse and improve the overall structure of the program. Let’s know about these concepts briefly below.
Subroutines
A subroutine is a self-contained section of code within a CLLE program that is defined to perform a specific task or set of related tasks. It has a unique name that allows the program to call and execute the subroutine as needed. This helps the developer of the CLLE program to reuse the code as many times as they need in their code without having to rewrite the same code for the functionality again and again.
Subroutines in CLLE
The Subroutine (SUBR) command is used in a CL program or procedure, along with the End Subroutine (ENDSUBR) command, to delimit the group of commands that define a subroutine. Let’s look at these commands one by one along with the two other important commands which are widely used when using subroutines in CLLE.
- SUBR: The SUBR command is used in the CLLE program to mark the beginning of the subroutine block. It has the following syntax:
SUBR SUBR(Subroutine_Name)
- ENDSUBR: The ENDSUBR command is used in the CLLE program to mark the termination of the subroutine block that began with the SUBR command.
- RTNSUBR: The optional RTNSUBR command is used to return a value and exit the subroutine that has been called.
RTNSUBR RTNVAL(INTVALUE)
- CALLSUBR: The CALLSUBR command can be used anywhere in the CLLE program to call the subroutine block and executes the code written inside it. The CALLSUBR command has the following syntax:
CALLSUBR SUBR(Subroutine_Name)
Subroutines are physically located in your source code following your main program logic and prior to the ENDPGM command. You can have many subroutines within your program, each delimited by paired SUBR and ENDSUBR commands.
The SUBR command has one parameter, SUBR, which is used to name the subroutine. This name is then used with the SUBR parameter of the CALLSUBR command to identify which subroutine is to be run. The ENDSUBR command defines the end of the common logic that started with the previous SUBR command. The ENDSUBR command has one parameter, RTNVAL, which can be used to specify a return value that can be returned to the caller of the subroutine.
The CALLSUBR command has two parameters: SUBR, which identifies the subroutine to call, and RTNVAL, which can optionally identify a CL variable to receive the return value of the called subroutine. There is also a Return from subroutine command, RTNSUBR, which can be used to immediately return control to the calling CALLSUBR command without having to run the ENDSUBR command. The RTNSUBR command also has one parameter, RTNVAL, which, like ENDSUBR, allows you to identify a return value to be returned to the calling CALLSUBR.
Example of CLLE program:
Let’s look at the below example of the CLLE program that uses a subroutine inside it.
CLLE Snippet showing subroutine.
In the above CLLE source snippet we have used the subroutine to perform a basic arithmetic addition operation on two numbers namely &NUM1 and &NUM2 and we are storing the result of the two numbers into &SUM.
In the above example we have used the CALLSUBR command to call the subroutine ADDSUBR. This subroutine is defined between the lines 011.00 and 012.00 as shown above. Inside the subroutine definition we have written the logic of the sum using the CHGVAR command.
We can use this subroutine as many times as we want and hence it increases the reusability of the code written inside the subroutine definition.
Procedures
In Integrated Language Environment, procedures are modular units of code that encapsulate a set of operations or logic ILE is an architectural framework used in IBM’s AS/400 and IBM i series systems allowing for integration of different programming languages like RPG. The procedure definition involves specifying the details and structure of a procedure in programming language and its fundamental step in creating a modular and usable piece of code that can be called or invoked from other parts of a programs.
The sub procedures are just like functions that we use in modern programming languages. There is a difference between subroutines and procedures as follows:
- You can pass parameters to a subprocedure, even passing by value.
- The parameters passed to a subprocedure and those received by it are checked at compile time for consistency. This helps to reduce run-time errors, which can be more costly.
- Names defined in a subprocedure are not visible outside the subprocedure.
- You can call subprocedures recursively.
- You can call the subprocedure from outside the module, if it is exported.
Procedures in CLLE
A CL procedure is a group of CL commands that tells the system where to get input, how to process it, and where to place the results. The procedure is assigned a name by which it can then be called by other procedures or bound into a program and called. As with other kinds of procedures, you must enter CL procedure source statements, compile, and bind them before you can run the procedure.
CL procedures can be written for many purposes, including:
- To control the sequence of processing and calling of other programs or procedures.
- To display a menu and run commands based on options selected from that menu. This makes the workstation user’s job easier and reduces errors.
- To read a database file.
- To handle error conditions issued from commands, programs, or procedures, by monitoring for specific messages.
- To control the operation of an application by establishing variables used in the application, such as date, time, and external indicators.
- To provide predefined functions for the system operator, such as starting a subsystem or saving files. This reduces the number of commands the operator uses regularly, and it ensures that system operations are performed consistently.
In CLLE, the CALL command is used to call the program whereas to call the procedure we use the CALLPRC command.
Example of CLLE program:
Let’s look at the below example of the CLLE program that uses a sub-procedure inside it.
CLLE Snippet showing sub-procedure:
The above CLLE program as we can see, uses the CALLPRC command to call the external procedure named MERGPROC with the VALUE1 and VALUE2 as the parameters.
According to the above CLLE snippet the parameters passed in the CALLPRC command would have the following values:
VALUE1 = ROHAN
VALUE2 = SINGH
Let’s check the source of the module containing the MERGPROC:-
As we can see above the logic of the concatenation of the values passed from the CLLE program has been written in the source. This procedure returns the concatenated value at the end of program to the CLLE program we saw above and displays the output as shown:
Data Structure
Introduction
Data structures are a powerful tool that can make your CL programs more efficient and easier to read and maintain. By using data structures, you can group related data together and reduce the amount of code that you need to write.
Data structures in CL on the AS400 can be created using defined variables. A defined variable is a variable that is based on a portion of another variable. This allows you to group related data together and to reference it more easily. To create a defined variable, you use the DCL VAR command with the STG(*DEFINED) and DEFVAR parameters.
The term STG(*DEFINED) means that this variable is another name for part of another variable. The DEFVAR parameter tells which variable this one is based on and the position at which this variable overlays the other.
Here some of the usages of using data structures in CL:
Improved efficiency:Data structures can help to improve the efficiency of your CL programs by reducing the amount of code that you need to write and by making it easier to access and manipulate data.
Increased readability and maintainability: Data structures can help to make your CL programs more readable and maintainable by grouping related data together and by giving your data meaningful names.
Reduced errors: Data structures can help to reduce errors in your CL programs by providing a way to validate data before it is used.
Restrictions-:
- CLLE data structures are limited to 64 KB in size.
- Arrays and pointers are not permitted in CLLE data structures.
- Members that are other data structures are not permitted in CLLE data structures.
- Nested structures are not permitted in CLLE data structures.
- Variable-length members cannot be found in CLLE data structures.
Compatibility -:
Field Data Types: Ensure that the data types of fields within a data structure are compatible with the data you intend to store in them. IBM i supports various data types, including character, numeric, date, and time types.
Compatibility with Embedded SQL:
If you use embedded SQL in your CLLE programs, the data structures you define should align with the structure of the database tables you are interacting with. Field names in your data structures should match the column names in SQL statements for proper binding.
Naming Conventions:
Follow consistent naming conventions for your data structures and fields. This helps maintain code readability and makes it easier to work with other developers’ code.
Performance Optimization:
Depending on your specific application and performance requirements, you may need to optimize your data structures for efficient access and processing.
Examples
The following example shows how to create a defined variable for an employee record:
DCL VAR(&EMPREC) TYPE(*CHAR) LEN(77)
DCL VAR(&EMPNUM) TYPE(*CHAR) LEN(6) STG(*DEFINED) DEFVAR(&EMPREC 1)
DCL VAR(&EMPNAME) TYPE(*CHAR) LEN(20) STG(*DEFINED) DEFVAR(&EMPREC 7)
This creates a defined variable called &EMPREC that is 77 characters long. The &EMPNUM and &EMPNAME variables are defined as being based on the first 6 and 20 characters of &EMPREC, respectively.
Once you have defined your defined variables, you can use them like any other variable in your CL program. For example, the following code shows how to print the employee’s name and number to the console:
DSPMSG MSG(&EMPNAME)
DSPMSG MSG(&EMPNUM)
Defined variables can be used to create complex data structures, such as arrays and linked lists. They can also be used to pass data between CL programs and other programs, such as RPG programs.
Here is an example of how to use a defined variable to pass data to an RPG program:
DCL VAR(&EMPREC) TYPE(*CHAR) LEN(77)
DCL VAR(&EMPNUM) TYPE(*CHAR) LEN(6) STG(*DEFINED) DEFVAR(&CUSTREC 1)
DCL VAR(&EMPNAME) TYPE(*CHAR) LEN(20) STG(*DEFINED) DEFVAR(&CUSTREC 7)
Assign values to the defined variables.
CALLP RPGPGM
PARM(&EMPREC)
Code example:
In the above code:
DCL declares a data structure named DATASTRUCT that is 50 characters long and containing multiple fields &FLD1, &FLD2, &FLD3, &FLD4 of different data types and are defined as being based on the first 10 and 31 characters of &DATASTRUCT, respectively.
STG(*DEFINED) – Storage: the value for this variable is specified in the variable defined in the DEFVAR parameter.
DEFVAR(&DATA_STRCT ?) – Defined on variable specifies the variable that contains this subfield, and its starting position.
Handling Data Areas
- Understanding Data AreasData areas are named permanent storage locations in the IBM i system that can hold several types of data, including character, numeric, or logical values. They are usually defined in a library and are identified by a unique name. The purpose of this storage is to pass information within multiple jobs.The main uses of data area can be:
- To store job information that is needed to run a group of jobs simultaneously.
- They are used in auto-generation of numbers e.g., next account no. generation, next invoice no. generation, next order no. generation etc.
- Creating a Data AreaIn CL programming, you can create a data area using the `CRTDTAARA` command.Like:
CRTDTAARA DTAARA(mylib/mydata) TYPE(*CHAR) LEN(10) VALUE('InitialValue')
Example:
- Reading Data from a Data Area With the RTVDTAARA (Retrieve Data Area) command in CL, you can retrieve data from a data area.Example:
The Display Data Area (DSPDTAARA) command displays the attributes and value of the specified data area. The following attributes are displayed: the type and length of the data area, the library where the data area is located (there is no library associated with a local data area, the group data area, or the program initialization parameter data area), and the text describing the data area.
Example:
- Writing Data to a Data AreaTo write data to a data area, you can use the `CHGDTAARA` (Change Data Area) command.To change the full Information,
like:CHGDTAARA DTAARA(mylib/mydata) VALUE('NewValue')
Example:
To change the partial Information, like:
CHGDTAARA DTAARA(mylib/mydata (Substring starting position Substring length)) VALUE('NewValue')
- Handling Data Area ErrorsHandling data area failures with the MONMSG command is a typical solution in CL programming. When error circumstances are encountered, MONMSG is used to monitor them and execute error-handling methods, allowing for the graceful handling of exceptions connected to data areas.Example:
- Synchronizing Data AccessIn situations where multiple programs are accessing the same data area simultaneously, you should use synchronization mechanisms, such as locking, to maintain data integrity.
- Cleaning Up Data AreasWhen you no longer need a data area, you can use the `DLTDTAARA` (Delete Data Area) command to remove it from the system.
Like,
DLTDTAARA DTAARA(mylib/mydata)
Example:
Limitations of Data Areas
Handling data areas from CL (Control Language) programming in RPGLE (Report Program Generator) has certain limitations and considerations that you should be aware of to use them effectively. Here are some important restrictions:
- Data Area Size Limitations: The maximum length specified during creation limits the size of data areas. The maximum length depends on the data area type (e.g., *CHAR, *DEC, *LGL ). For instance, a character data area (*CHAR) typically has a maximum length of 2000 characters.
- Limited Data Types: A CL data area can contain only certain types of data, such as character (*CHAR), decimal (*DEC), and logical (*LGL). Besides integer and float types, other data types commonly used in RPGLE are not currently supported.
- No Arrays or Record Formats: There is no support for array or record format structures in data areas. Depending on the type and length of data, they can only hold a single value.
- Limited Error Handling: Error handling in CL is limited compared to RPGLE. MONMSG can be used to monitor for errors during data area operations, but its error handling is less granular than RPGLE’s.
Handling Data Queues
Data Queues(*DTAQ) are the objects useful to carry out data transfer within a job or between multiple jobs. Once a data Queue is created, it can be utilized to send and receive data multiple times asynchronously.
Data Queues are mainly of 3 types:
- 1. Standard Data Queue(*STD): These data queues can mainly transfer data between different jobs and programs in a single IBM i system.
- 2. Distributed data management Data Queue(*DDM): These data queues are created for the scenarios when communication between two different IBM i systems is required.
- 3. Display Data Queue(*DSP): If a program wants to access data from a data queue while using display files then this data queue can be created. To make use of these data queues, we can specify the name of the data queue in the DTAQ parameter while creating a display file.
The sequence of storing and retrieving entries on a data queue is as follows:
- *FIFO (First-in, first-out): The entry sent first to the data queue will be retrieved first.
- *LIFO (First-in, first-out): The entry sent last to the data queue will be retrieved first.
- *KEYED: The sequence of retrieving the entries will depend on the key value.
Usage
There are multiple commands and APIs available in IBM i to create, delete and work with the data queues. Using Data Queue enhances the overall performance of an interactive program by reducing the response time.
Useful Commands
Commands available in IBM i to handle Data Queues:
- CRTDTAQ (Create Data Queue): This command will create a Data Queue object in particular library.
Command Syntax for *STD data queue:
CRTDTAQ DTAQ(*CURLIB/PIOSTDDTAQ)
TYPE(*STD)
MAXLEN(1000)
SEQ(*FIFO)
TEXT(‘STD DATA QUEUE')
Command Syntax for *DDM data queue:
CRTDTAQ DTAQ(*CURLIB/ PIODDMDTAQ)
TYPE(*DDM)
RMTDTAQ(LIBNAME/RMTDTAQ1)
RMTLOCNAME(*RDB)
RDB(RDBNAME)
TEXT(‘DDM DATA QUEUE')
Command Syntax for *DSP data queue:
CRTDTAQ DTAQ(*CURLIB/ PIODSPDTAQ)
TYPE(*DSP)
MAXLEN(100)
TEXT(‘DSP DATA QUEUE')
Important parameters of this command are as follows:
- 1. DTAQ:
Data queue: Describes the name of the data queue object to be created.
Library: Describes the library name in which the data queue object will be created. Its default value is *CURLIB (The current library of the job).
CALL PGM(QSNDDTAQ): This command will call an API ‘QSNDDTAQ’, through which we can send data to a data queue.
Command Syntax:
CALL PGM(QSNDDTAQ) PARM(<dataQueue> <Library> <LengthOfData> <Data>)
Example-
CALL PGM(QSNDDTAQ) PARM(‘PIODTAQ’ ‘PIOLIB’ ‘10’ ‘TEST DATA QUEUE’)
Important parameters of this command are as follows:
- 1. Data Queue: Describes the name of the data queue object to which data will be sent. This parameter data type is Char, and the length is 10.
- 2. Library: Describes the library name in which the data queue object is present. This parameter data type is Char, and the length is 10.
- 3. Length: Describes the length of the data to be sent. This parameter data type is Packed and length 5,0.
- 4. Data: Describes the data to be sent to the data queue. This parameter data type is Char.
CALL PGM(QRCVDTAQ): This command will call an API ‘QRCVDTAQ’, through which we can receive data to a data queue.
Command Syntax:
CALL PGM(QRCVDTAQ) PARM(<dataQueue> <Library> <Length> <Data> <waitTime>)
Example:
CALL PGM(QRCVDTAQ) PARM(‘PIODTAQ’ ‘PIOLIB’ ‘10’ ‘’ ‘0’)
Important parameters of this command are as follows:
- 1. Data Queue: Describes the name of the data queue object from which data will be received. This parameter data type is Char, and the length is 10.
- 2. Library: Describes the library name in which the data queue object is present. This parameter data type is Char, and the length is 10.
- 3. Length: Describes the length of the data to be received. This parameter data type is Packed, and the length is 5,0.
- 4. Data: This parameter will receive the data. Its data type is Char.
- 5. WaitTime: Describes the delay to be made while receiving data from a data queue. This parameter data type is Packed, and the length is 5,0.
Note: If WaitTime is -1, the data will be received from data queue as soon as it enters the data queue.
- DLTDTAQ (Delete Data Queue): This command will delete the Data Queue object present in particular library.
Command Syntax:
DLTDTAQ DTAQ(PIOLIB/PIODTAQ)
Restrictions
- – The maximum value for the MAXLEN parameter can be 64512.
- – Data queues can send and receive data of Character type only.
- – MAXLEN & SEQ parameter is not valid while creating a data queue of type *DDM.
- – A *DSP data queue cannot be created with the sequence as *KEYED.
Code Example:
The above code example is a CLLE program that creates a data queue of type *STD & sequence as *FIFO.
Then ‘QSNDDTAQ’ API is called to send the data to the PIODTAQ data queue.
We can send data to a single data queue multiple time. Data from the VAR1 variable is sent first & then data from the VAR2 variable is sent.
The second code example is a CLLE program that will receive the data from the data queue by calling the ‘QRCVDTAQ’ API.
When the ‘QRCVDTAQ’ API is called for the first time in the above program, data sent from VAR1 will be retrieved first & the same will be displayed while executing the SNDUSRMSG command for the first time.
When the ‘QRCVDTAQ’ API is called for the second time in the above program, data sent after VAR1, i.e. VAR2 will be retrieved & the same will be displayed while executing the SNDUSRMSG command for the second time.
This is because PIODTAQ will retrieve data in *FIFO sequence.
Built-in Function
%CHAR
The %CHAR built-in function in CL is used to convert logical, decimal, integer, or unsigned integer data into character format.
SYNTAX:
- Convert-argument: The convert-argumentis a CL variable with the type of *LGL, *DEC, *INT, or *UINT.
EXAMPLE:
- %CHAR built-in function converted the &NUM1, &LEN, &SIZE, and & LGLVAR variable, to character type, which has type *DEC, *UINT, *INT, and *LGL respectively.
- The &RESULT variable having *CHAR type will store the result in character format.
%DEC
%DEC built-in function is used to convert character, logical, decimal, integer, or unsigned integer data into packed decimal format.
SYNTAX:
- Convert-argument: The convert-argument is a CL variable with the type of *CHAR, *LGL, *DEC, *INT, or *UINT.
- Total-digits & decimal-places: total-digits and decimal-places parameters are optional. They will take default values, Based on data type.
EXAMPLE:
- %DEC built-in function converted the &STR1, &LGLVAR, &NUM1, and &NUM2 variable , to decimal type, which has type *CHAR, *LGL, *INT, and *UINT respectively.
- The &RESULT variable having *DEC type will store the result in packed decimal format.
%INT
%INT built-in function is used to convert character, logical, decimal, or unsigned integer data to integer format.
SYNTAX:
- Convert-argument: The convert-argument is a CL variable with the type of *CHAR, *LGL, *DEC or *UINT.
EXAMPLE:
- %INT built-in function converted the &STR1, &LGLVAR, &NUM1, and &NUM2 variable, to integer type, which has type *CHAR, *LGL, *DEC, and *UINT respectively.
- The &RESULT variable having *INT type will store the result in integer format.
%LEN
%LEN built-in function is used to return the length of the numeric or character variable.
SYNTAX:
- Variable-argument: The variable-argument is a CL variable with the type of *CHAR, *DEC, *INT, or *UINT.
- If length is not defined for the numeric and character variable it will return the default length.
EXAMPLE:
- The length of variables &STR1, &STR2, &NUM1, &NUM2, &NUM3, and &NUM4 will be 32, 30, 16, 6, 10, and 5 respectively stored in &LEN variable.
- The value 5 will be returned for a 2-byte *INT or *UINT variable. And value 10 will be returned for a 4-byte *INT or *UINT.
%LOWER
%LOWER built-in function returns a character string of the same length as the argument passed in, but with every uppercase letter changed to its corresponding lowercase letter.
SYNTAX:
- input-string: input-string is a CL variable with the type of *CHAR.
- The CCSID parameter is optional and defaults to the job CCSID.
EXAMPLE:
&STR1 variable contains the value “HI THERE” in uppercase letters. %LOWER built-in function will return the value “hi there” in lowercase letters.
%UPPER
%UPPER built-in function returns a character string of the same length as the argument passed in, but with every lowercase letter changed to its corresponding uppercase letter.
SYNTAX:
- input-string: input-string is a CL variable with the type of *CHAR.
- The CCSID parameter is optional and defaults to the job CCSID.
EXAMPLE:
&STR1 variable contains the value “hi there” in lowercase letters. %UPPER built-in function will return the value “HI THERE” in uppercase letters.
%PARMS
%PARMS built-in function is used to return the number of parameters that were passed to the program in which %PARMS is used.
SYNTAX:
EXAMPLE:
The following is the source for EMPDATA.
- Three parameters were passed to the program which was called by a program call.
- %PARMS built-in function will return the 3 parameters and “3 parms were passed” will be the result of program.
%CHECK:
%CHECK is used to find the first position of base string where a specific character is not available in the test string from left to right. A 0 is returned when all characters match. It is supported in arithmetic expressions and conditional statements.
SYNTAX:
- Comparator-String: it must be either a cl character variable or a character literal. The comparator string specifies the characters to search for in the base string.
- Base-String: It can be a cl character variable or *LDA. Base string refers to the string against which the comparison is made.
- Starting-position: It is optional and defaults to 1 and specifies where checking begins.
EXAMPLE:
- Look for the first character that isn’t an asterisk(*) or a dollar sign($). From left to right, the characters in the variable &AMOUNT are examined.
- The CHGVAR command assigns the value 8 to the cl variable &POS since the eighth character is the first one that is neither an asterisk nor a dollar sign.
%CHECKR:
%CHECKR is used to find the first position of base string where a specific character is not available in the test string from right to left. 0 is returned when all characters match. It is supported in arithmetic expressions and conditional statements.
SYNTAX:
EXAMPLE:
- &COM contains the comparator string (‘$* ‘).
- &AMT contains the base string (‘$***5.27 ‘).
- &SPOST stores the leftmost position where a character not in the comparator string appears.
- &EPOST stores the rightmost position where a character not in the comparator string appears.
- &LENT calculates the number of characters between these two positions.
- &DECS Extracts The Relevant Substring And Converts It To A Decimal Cl Variable.
%SCAN:
The %scan built-in function in cl is a powerful tool for string manipulation.
%scan gives back a search argument’s initial position in the source string.
The function returns 0 if the search argument cannot be found.
%scan can be used anywhere an arithmetic expression is supported by CL.
SYNTAX:
- Search Argument: a literal character or a CL character variable. It is the substring that you want to search for within a larger string.
- Source-String: *LDA or a CL character variable. The contents of the local data area for the job are scanned by the scan function when *LDA.
- It refers to the string that is searched for occurrences of a specified substring.
- Starting Position (Optional): this is the first location in the source string where the search starts by default.
EXAMPLE:
- A message is issued if the string “jonny” cannot be located in the variable &firstname.
- Because the scan is case sensitive, if &firstname contains the value “jonny,” a search for “Jonny” will not yield a positive result.
%SUBSTRING OR %SST:
You can work with character strings using CLLE’S built-in %substring (or %sst) function.
A character string generated by the %substring function is a subset of an already-existing character string.
SYNTAX:
Alternatively, it can be written as:
We can also use %SST with the special value *LDA to indicate that the substring function operates on the contents of the local data area.
- Character-variable-name: The name of the CL character variable or the special value *LDA. Character variable name refers to the name of the variable containing the string from which you want to extract a substring.
- Starting position: The position (which can be a variable name) where the substring begins (cannot be 0 or negative). Specifies the position within the source string from which the substring extraction begins.
- Length: The length (which can also be a variable name) of the substring (cannot be 0 or negative).
The program CUS210 is invoked if the initial two positions of &VAR1 and &VAR2 match.
%TRIM:
Leading and trailing characters can be omitted from character strings using the %trim. The %trim function serves two purposes:
Trim Leading and Trailing Blanks: This function removes leading and trailing blank spaces from a character string when it is used with a single parameter.
Custom Trim: This function removes expected leading and trailing characters specified in the second parameter when it is used with two parameters.
SYNTAX:
- Character-variable-name: Refers variable name that we want to trim.
- Character-to-trim: Refers characters that we want to trim.
- If the characters-to-trim parameter is specified, it must be either a cl character variable or a character literal.
- If, after trimming, no characters are left, the function produces a string of blank characters.
EXAMPLE:
- Eliminate leading and trailing whitespace characters.
- After trimming the leading and trailing blanks from the CL variables &FNAME and &LNAME, the remaining strings are concatenated with the *BCAT operator, leaving a single blank between the two values.
- Next, the concatenated string is allocated to the cl variable &sname
%TRIML:
The built-in function %triml is used to manipulate strings by eliminating only the leading characters.
SYNTAX:
- Character-variable-name: Refers variable name that we want to trim.
- Character-to-trim: Refers characters that we want to trim.
- If the characters-to-trim parameter is specified, it must be either a cl character variable or a character literal.
- If, after leading, no characters are left, the function produces a string of blank characters.
EXAMPLE:
- The letters that remain (6.37) are allocated to cl variable &TRIMMEDAMT, while all dollar signs and blanks are removed from the beginning of cl variable &AMT.
- Decimal variable &decvar receives the numeric value supplied to the character variable &TRIMMEDAMT.
%TRIMR:
The %trimr function removes any trailing characters (usually blank spaces) from a character string.
SYNTAX:
- Character-variable-name: Refers variable name that we want to trim.
- Character-to-trim: Refers characters that we want to trim.
- If the characters-to-trim parameter is specified, it must be either a cL character variable or a character literal.
- If, after trailing, no characters are left, the function produces a string of blank characters.
EXAMPLE:
- The CL variables &FNAME and &LNAME have their following blank characters removed, and the resulting strings are concatenated using the *cat operator.
- Next, the concatenated string is allocated to the CL variable &sname.