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
Report Program Generator (RPG)
Logic Cycle
Introduction
The RPG cycle simplifies the development process by automatically handling file operations, calculations, and report generation. Programmers can focus on business rules and logic without explicitly writing code for file handling and other repetitive tasks. The primary procedure goes through the RPG cycle, which is a set of sequential steps, for every record that is read.
A portion of an RPG program’s logic is provided by the RPG compiler. The program cycle, often known as the logic cycle or RPG cycle, is provided by the compiler for a cycle-main procedure.
The program cycle for a cycle-main procedure is provided by the RPG compiler.
The following steps are part of the program cycle:
- Implicit opening of files and locking of data areas
- Reading and processing of records
- Any calculations or report printing
- Implicit closing of files and unlocking of data areas
RPG Life Cycle Stages
There are multiple stages in the AS/400 RPG (Report Program Generator) logic cycle:
- Compile:A high-level language is used to write RPG programs, which are subsequently transformed into machine-readable code by a compiler. The program is converted into machine code and checked for syntax issues during compilation.
- Bind:The software must be bound to the relevant database files and other resources it interacts with after compilation. Program access to required files and data structures is guaranteed via binding.
- Activation: The RPG program goes through an activation process when a user starts it. This includes communicating with the database and assigning resources like RAM.
- Execution: Based on the input and program logic, the stated operations are carried out by the program’s logic. Calculations, report generation, and record processing are common tasks of RPG systems.
- Termination: The program goes through a phase of termination after its execution is finished. Any temporary storage is released, and resources are reallocated.
- Output: Reports and files are created either during or after the execution phase of the RPG program, if any. When the RPG software is run again, the cycle is repeated as necessary. The AS/400 system’s RPG programs run in an ordered manner thanks to this cycle.
Usage in the RPG life cycle
In the RPG life cycle context, the term “usage” refers to the many activities and reasons for which RPG (Report Program Generator) programs are used during their lives on AS/400 or IBMi systems. RPG programs are often employed at different points of their lifecycle, as shown below:
Development: RPG programs are generated during development to implement specific business logic or functionality. SEU (Source Entry Utility) and RDi (Rational Developer for i) are tools used by developers to write RPG code.
Testing: After development, RPG programs are tested to ensure they work as intended and meet the specifications. This entails several forms of testing, including unit testing, integration testing, and system testing.
Integration: RPG programs are integrated with other system components or third-party applications as required. This can include interacting with databases, phoning other programs or services, and transferring data with external systems.
Deployment: Once testing is completed and the programs are considered ready for production use, they are moved to production settings. This includes transferring compiled RPG objects (such as programs and modules) to the production system and making any necessary configuration adjustments.
Maintenance: RPG programs require maintenance throughout their lifecycle to address errors, adapt to changing business requirements, and increase performance or usefulness. Bug repairs, additions, and optimizations are all possible maintenance operations.
Monitoring and Support: Once deployed, RPG programs are monitored to ensure they run successfully in production situations. Support teams are responsible for resolving any difficulties that emerge and assisting users as needed.
Overall, RPG programs play an important role in the IBM I environment, acting as the foundation for many commercial applications that operate on these systems. Their use throughout the lifecycle enables the efficiency and ongoing improvement of the systems they support.
Restrictions in the RPG life cycle
Restrictions in the RPG life cycle might include:
Limited tooling: When compared to more current languages, RPG development tools may be limited, affecting development and maintenance efficiency.
Legacy codebase: Working with legacy RPG codebases can be difficult due to outdated coding methods and a lack of documentation.
Platform dependencies: RPG programs are often strongly connected with the IBM I platform, limiting portability and interoperability with other systems.
Skill availability: Because RPG programming is becoming less popular in comparison to more recent languages, finding developers with competence in this area may be difficult.
Performance constraints: Older RPG applications may not fully utilize the capabilities of newer hardware, resulting in potential performance bottlenecks.
Addressing these limits frequently requires a combination of modernization activities, such as reworking legacy code, adopting newer development tools, and educating or hiring engineers with competence in both RPG and current technologies.
Built-in Functions
%ABS:
The absolute value of the numeric expression specified as the parameter is returned by %ABS. The value is returned unchanged if the numeric expression’s value is non-negative.
To find the Absolute value (Positive value) of a numerical expression, use the %ABS function. When we want the expression results to be positive, we can use the %ABS () function.
Syntax: %ABS (numeric expression)
Example:
Result
%DIFF:
To find the difference between two date, time, or timestamp values, use the %DIFF function. The difference (duration) between two date or time data is generated by %DIFF.
The types of the first and second parameters must be the same or compatible.
The combinations mentioned below can be used to obtain the difference:
- Differences between the two dates
- Difference between the two times
- Difference between two timestamps
- Difference between Date and timestamp (only the time portion of the timestamp)
- Difference between Time and timestamp (only the time portion of the timestamp)
The unit of evaluating for the difference is indicated by the third parameter. The units mentioned below are Valid:
- Difference between two dates or between a timestamp and a date: *DAYS, *MONTHS, *YEARS.
- *SECONDS, *MINUTES, *HOURS, for two times, or a time and a timestamp.
- The *MSECONDS, *SECONDS, *MINUTES, *HOURS, *DAYS, *MONTHS, and *YEARS timestamps differ from each other.
Syntax:%DIFF(op1 : op2 : unit {: frac })
Example:
Result
%DIV:
The integer part of the quotient obtained by dividing operands n by m is returned by the function %DIV.
It is required that the two operands have decimal values with zero decimal places.
The result is packed numeric if the operand is either a zoned, packed, or binary numeric value. The result is an integer if either operand has an integer numeric value. If not, the outcome is an unsigned number.
Numerical operands that float are prohibited.
If the operands are constants that can fit in 8-byte integers or unsigned fields, constant folding is applied to the built-in function.
In this scenario, the definition specifications can be used to code the built-in %DIV function.
Syntax:%DIV(n:m)
Example:
Result
%EDITC:
Numerical values can be formatted with special characters such as asterisk (*), period (. ), comma (, ), cent sign (¢), pound sign (£), dollar sign ($), minus sign (-), credit sign (CR), etc.
using the %EDITC function. To produce a date format, it can also be used to suppress zeros or format numbers with a slash (/).
Real-world scenarios frequently need us to provide reports with amount fields that look like $12,345.67-, $12,345.67CR, or ‘***12345.67-‘ rather than showing the amount as -12,345.67.
We can use the %EDITC Function in such report production programs to generate the results we desire.
Syntax:%EDITC(numeric : editcode {: *ASTFILL | *CURSYM | currency-symbol})
Here, the input numeric value that we wish to change is the first parameter.
2nd parameter is the edit code option used to generate the required edited string.
Another format choice, the third parameter, is used to create the necessary manipulated string.
3rd parameter is an optional parameter.
Example:
Result
%EDITFLT:
The numeric expression’s value is converted to the float’s character external display representation by using %EDITFLT. Either 14 or 23 characters are the result.
The final result is 14 characters if the parameter is a 4-byte float field. If not, there are 23 characters.
When a definition specification keyword takes in a parameter, it must be either a built-in function or a numeric literal, float literal, or name of a numeric valued constant.
Constant folding is applied when stated in an expression, provided that the numeric expression has a constant value.
Syntax:%EDITFLT(numeric expression)
Example:
Result
%EDITW:
Numerical values with special characters such as asterisk(*), period(. ),comma(. ), cent sign(«), dollar sign($), minus sign(-), credit sign(CR), percentage(%), etc. can be formatted using the %EDITW function.
Additionally, it can be used to format a number in date format by using a slash(/).
Real-world scenarios frequently need us to provide reports with amount fields that look like $12,345.67-, $12,345.67CR, or ‘***12345.67-‘ rather than showing the amount as -12,345.67.
We can use the %EDITW Function in such report production programs to generate the output we desire.
Syntax:%EDITW(numeric : editword)
The input numeric value that we wish to modify is the first argument.
2nd parameter is the edit word option used to generate the required edited string.
Example:
Result
%ELEM:
The %ELEM function can be used to get the total number of elements present in a table, array, or multiple-occurrence data structure.
Stated alternatively, this function allows us to get the dimension.
Syntax: %ELEM(table_name)
%ELEM(array_name)
%ELEM(multiple_occurrence_data_structure_name)
Example:
Result
%EOF (Return End or Beginning of File Condition)
When carrying out a file action equal to the resultant indicator, this built-in function is utilized to identify end-of-file, beginning-of-file, or subfile full situations.
Therefore, we only use %EOF to determine whether the file’s end has been reached rather than looking for any resulting indications.
%EOF returns ‘1’ if the whole condition of the end-of-file, beginning-of-file, or subfile is detected; if not, it returns ‘0’.
If the file ends, READ, READC, and READE return %EOF=*ON.
If the beginning of the file is reached, READP and READPE return %EOF=*ON.
If a subfile detail record is provided with a subfile-full condition, the WRITE operation returns %EOF=*ON.
CHAIN operation on successful search sets %EOF=*OFF if %EOF=*ON and we execute the CHAIN operation.
In the event where %EOF=*ON occurs and a CHAIN operation is carried out, the successful search sets %EOF=*OFF.
On successful operations, SETGT, SETLL, OPEN, and %EOF=*OFF are set.
Syntax: %EOF(file_name)
Example:
%EQUAL:
In addition to the two operation codes SETLL and LOOKUP, %EQUAL is used.
It is used by the SETLL operation to indicate that it detected a record in the file with a key equal to that of the value specified in Factor 1.
Therefore, to verify that the record is present, we can use SETLL along with %EQUAL.
For the SETLL operation, this function returns ‘1’ if a record is present whose key or relative record number is mentioned in factor-1.
If an element is found that exactly matches the element in factor-1, this method returns ‘1’ for the LOOKUP operation.
Syntax: %EQUAL(file_name);
Example:
%LOWER :
Yields the string operand after it has been partially or fully converted to lowercase.
The string that needs to be changed from uppercase to lowercase is the first operand.
It may be UCS-2 or alphanumeric in type.
The conversion’s starting point is represented by the second operand.
Its value must be between one and the string’s length, and it must be a numeric expression with zero decimal places. It’s Optional.
The conversion begins at the first position in the string if it is not specified.
The length to be converted is the third operand. It must be less than or equal to the length of the string beginning at the start point, and it must be a numeric expression with zero decimal places. It might be zero. It’s not required.
Syntax: %LOWER(string {: start { : length } })
Example:
Result
%UPPER:
%UPPER returns the string operand, with all or part of the operand converted to upper case.
The conversion’s starting point is represented by the second operand.
Its value must be between one and the string’s length, and it must be a numeric expression with zero decimal places. It’s Optional. The conversion begins at the first position in the string if it is not specified.
The length to be converted is the third operand.
It must be less than or equal to the length of the string beginning at the start point, and it must be a numeric expression with zero decimal places. It might be zero. It’s not required.
Syntax: %UPPER(string {: start { : length } })
Example:
Result
%MAX:
The maximum value of its operands is returned by %MAX.
The operands must all have data types that are compatible for comparison with each other.
In the case that one item in the list is alphanumeric, the others in the list may be graphic, UCS-2, or alphanumeric. The others can be packed as integers, unsigned integers, binary decimal, float, zoned numeric, or packed numeric if one is packed numeric.
Operands cannot include items of type object or procedure-pointer.
There must be at least two operands. There is no practical upper limit for the number of operands.
Syntax: %MAX(item1 : item2 {: item3 { item4 … } })
Example:
Result
%MIN:
The minimum value of its operands is returned by %MIN.
The operands must all have data types that are compatible for comparison with each other
In the case that one item in the list is alphanumeric, the others in the list may be graphic, UCS-2, or alphanumeric.
The others can be packed as integers, unsigned integers, binary decimal, float, zoned numeric, or packed numeric if one is packed numeric.
Operands cannot include items of type object or procedure-pointer.
There must be at least two operands. There is no practical upper limit for the number of operands.
Syntax: %MIN(item1 : item2 {: item3 { item4 … } })
Example:
Result
%SCAN:
To determine the search argument’s first position in the source string, use the %SCAN function.
Position of the matching position is returned if a match is found; else, 0 is returned.
The search element that is being looked up in the source string is the function’s first parameter.
The source string that we are searching in is the second parameter.
The third parameter indicates the starting point for the search within the given string.
The type of the second argument should to match with the first. These parameters may be UCS-2, graphic, or character-based.
Seek arguments or source String can contain blanks in form of string or string padded with blank. Those blanks are also taken into consideration when performing the search.
Syntax: %SCAN(search argument : source string {: start position {: length}})
Example:
Result
%SCANR :
%SCANR returns the last position of the search argument in the source string, or 0 if it was not found.
The start position and length specify the substring of the source string to be searched.
The length and start positions are set to the default values of 1 and the remainder of the source string, respectively. The result is always the position in the source string even if the starting position is specified.
The search element that is being looked up in the source string is the function’s first parameter.
The source string that we are searching in is the second parameter.
The third parameter indicates the starting point for the search within the given string.
The type of the second argument should to match with the first. These parameters may be UCS-2, graphic, or character-based.
Seek arguments or source String can contain blanks in form of string or string padded with blank. Those blanks are also taken into consideration when performing the search.
Syntax: %SCANR(search argument : source string {: start position {: length}})
Example:
Result
%SCANRPL:
All instances of the scan string in the source string are replaced with the replacement string, and the resultant string is returned by the %SCANRPL function
Starting at the scan start position and continuing for the scan length is the search for the scan string.
The parts of the source string that are outside the range specified by the scan start position and the scan length are included in the result.
The first, second and third parameters must be of type character, graphic, or UCS-2. They may come in formats with variable lengths or set lengths.
Each of these factors needs to be CCSID and of the same type.
The starting position, expressed in characters, where the search for the scan string must begin is represented by the fourth argument. The start position is set to one by default if it is not given. The value could be anything from one to the source string’s current length.
The fifth parameter represents the number of characters in the source string to be scanned. If the parameter is not specified, the length defaults to remainder of the source string starting from the start position.
Syntax: %SCANRPL(scan string : replacement : source { : scan start { : scan length } } )
Example:
Result
%TRIM:
To remove blank space from a string on both sides, use the %TRIM function.
Other than blanks, it can also be used to trim characters. In argument 2, we can specify which characters should be removed.
Syntax: %TRIM(string {: characters to trim})
Example:
Result
%TRIML:
The %TRIML method is used to remove a string’s leading blank spaces.
Other than blanks, it can also be used to trim characters. In argument 2, we can specify which characters should be cut.
Syntax: %TRIML(string {: characters to trim})
Example:
Result
%TRIMR:
The %TRIMR function is used to remove a string’s trailing blank spaces.
Other than blanks, it can also be used to trim characters. In argument 2, we can specify which characters should be cut.
Syntax: %TRIMR(string {: characters to trim})
Example:
Result
%XLATE:
The string is translated by %XLATE based on the values of startpos, from, and to.
A list of characters that need to be replaced is contained in the first parameter, and the replacements are given in the second. The third character in to is replaced for every occurrence of the character in from, for instance, if the string contains the third character in from.
The string that needs to be translated is the third parameter. The translation’s starting point is the fourth parameter. Translation starts at position 1 by default.
The additional characters in the first parameter are ignored if it is longer than the second parameter.
The first three of parameters can belong to either character, graphic, or UCS-2 types. All three must have the same type.
Syntax: %XLATE(from:to:string{:startpos})
Example:
Result
%SUBST:
The string is partially extracted from any point using the %SUBST method.
The source string, from which we wish to extract a portion of the string, is the first parameter in this case.
The beginning point from which we will begin the string extraction process is the second argument.
The length to extract is the third argument.
Syntax: %SUBST(string:start{:length})
Example:
Result
%HOURS:
A number is converted to a duration (number of hours) using %HOURS.
This duration can be used to increase or decrease the value of a time or timestamp.
Therefore, we may obtain any past or future time by using %HOURS.
Syntax: %HOURS(number)
Example:
Result
%MINUTES:
A number is converted to a duration (number of minutes) using %MINUTES. This duration can be used to increase or decrease the value of a time or timestamp. Thus, we may obtain any past or future time by using %MINUTES.
Syntax: %MINUTES(number)
Example:
Result
%SECONDS:
To modify the duration of seconds in a time or timestamp, add a duration to the number using %SECONDS.
Syntax: %SECONDS(number)
Example:
Result
%SUBDT:
A subset of the data in a date, time, or timestamp value is extracted using %SUBDT.
It returns an unsigned numeric value.
The date, time, or timestamp value is the first parameter.
The part you wish to extract is the second parameter.
Syntax: %SUBDT(value : unit { : digits { : decpos } })
Example:
Result
%RANGE:
The IN operator is used with %RANGE. %RANGE can only be specified by following the IN operator; it does not return a value.
The IN operator determines to see if the first operand is within the range given by %RANGE when it is used with %RANGE.
The expression using the IN operator with %RANGE is true if the first operand of the IN operator is greater than or equal to the first operand of %RANGE and less than or equal to the second operand of %RANGE.
An array cannot be the IN operator’s initial operand.
The operands of %RANGE must be able to be compared to each other and to the first operand of the IN operator.
Syntax:
Example:
Result
%SQRT:
The square root of the given numeric expression is returned by the %SQRT function. If the operand is of type float, the result is of type float; otherwise, the result is packed decimal numeric. The parameter raises exception 00101 if its value is less than zero.
Syntax: %SQRT (numeric expression)
Example:
Result
%REPLACE
The segment of a string with the replacement string is used with the %REPLACE function.
Syntax: %REPLACE(replacement string: source string{:start position {:source length to replace}})
Example:
Result
%XFOOT:
The total of each element in the given numeric array expression is produced by using %XFOOT.
The precision of the result is the minimum that can hold the result of adding together all array elements, up to a maximum of 63 digits. The result’s decimal places are always the same as the array expression’s decimal places.
Syntax: %XFOOT (array-expression)
Example:
Result
%MSECONDS :
A number can be converted into a duration using %MSECONDS, which is able to be added to a time or timestamp value.
Only the plus or minus sign in an addition or subtraction expression can be followed by %MSECONDS. A time or timestamp must be the value that comes before the plus or minus sign. The result is a time or timestamp value with the appropriate number of microseconds added or subtracted. The resultant value is initially displayed in *ISO format.
Syntax: %MSECONDS(number)
Example:
Result
%ADDR :
A value of type basing pointer is returned by %ADDR. The address of the specified variable is the value. It may only be compared with and assigned to items of type basing pointer.
When *DATA is given as the second argument of %ADDR, the address of the data component of a variable-length field is returned by %ADDR.
The array index needs to be known at compile time if %ADDR with an array index parameter is used as a parameter for defining specification keywords INZ or CONST. Either a numerical literal or a numerical constant must be used as the index.
Syntax: %ADDR(variable)
%ADDR(varying-length variable : *DATA)
Example:
Result
%ALLOC:
A pointer to freshly allocated heap storage of the given length is returned by %ALLOC. The newly allocated storage is uninitialized.
The parameter must be a non-float numeric value with zero decimal places. The length must fall between 1 and the maximum dimension that is allowed.
The maximum size allowed depends on the type of heap storage used for RPG memory management operations due to the ALLOC keyword on the Control specification.
Syntax: %ALLOC(num)
Example:
Result
%BITAND :
The bit-wise ANDing of each argument’s bits is returned by %BITAND. That is, the result bit is ON when all of the corresponding bits in the arguments are ON, and OFF otherwise.
This built-in function accepts either character or numeric parameters. Numerical arguments are first converted to integer if they are not integer or unsigned. If the value does not fit in an 8-byte integer, a numeric overflow exception is issued.
There can be two or more arguments for %BITAND. Each parameter must be of the same type—a number or character. The types of the arguments and the result are the same.
Syntax: %BITAND(expr:expr{:expr…})
Example:
Result
%BITNOT:
%BITNOT returns the bit-wise inverse of the bits of the argument. In other words, the result bit is ON when the argument’s corresponding bit is OFF and OFF otherwise.
This built-in function accepts either a character or a number argument. Numerical arguments are first converted to integer if they are not integer or unsigned. If the value does not fit in an 8-byte integer, a numeric overflow exception is issued.
%BITNOT only accepts a single parameter. The types of the arguments and the result are the same. If all of the parameters are unsigned, the result for numerical arguments is unsigned; if not, it is an integer.
Syntax: %BITNOT(expr)
Example:
Result
%BITOR:
%BITOR returns the bit-wise ORing of the bits of all the arguments. In other words, the result bit is OFF otherwise and ON when any corresponding bit in the arguments is ON
This built-in function accepts either character or numeric parameters. Numerical arguments are first converted to integer if they are not integer or unsigned. If the value does not fit in an 8-byte integer, a numeric overflow exception is issued.
There may be two or more arguments for %BITOR. Each parameter must be of the same type—a number or character.
Syntax: %BITOR(expr:expr{:expr…})
Example:
Result
%SPLIT :
%SPLIT splits a string into an array of substrings. It returns a temporary array of the substrings.
%SPLIT can be used in calculation statements wherever an array can be used except:
- SORTA
- %ELEM
- %LOOKUP
- %SUBARR
The first operand is the string to be split. It can be alphanumeric, graphic, or UCS-2.
The second operand is the list of characters that indicate the end of each substring. It is optional. It must have the same type and CCSID as the first operand. If it is not specified, %SPLIT defaults to splitting at blanks.
If the length of the second operand is greater than 1, any of the characters in the second operand indicate the end of each substring.
For example, %SPLIT(‘abc.def-ghi’ : ‘.-‘) has two separator characters, ‘.’, and ‘-‘, so it returns an array with three elements: (‘abc’,’def’,’ghi’).
Syntax: %SPLIT(string {: separators })
Example:
Result
%BITXOR :
The bit-wise exclusive ORing of the two parameters’ bits is returned by %BITXOR. That is, the result bit is ON when just one of the corresponding bits in the arguments are ON, and OFF otherwise.
This built-in function accepts either a character or a number argument. Numerical arguments are first converted to integer if they are not integer or unsigned. If the value does not fit in an 8-byte integer, a numeric overflow exception is issued.
%BITXOR requires a pair of arguments. The types of the arguments and the result are the same. If all of the parameters are unsigned, the result for numerical arguments is unsigned; if not, it is an integer.
Syntax: %BITXOR(expr:expr)
Example:
Result
%Error :
If an error condition was encountered during the most recent operation using the requested extender ‘E,’ then %ERROR returns ‘1.
This is equivalent to having the operation’s error indicator turned on. Before an operation with extender ‘E’ specified begins, %ERROR is set to return ‘0’ and remains unchanged following the operation if no error occurs.
The built-in function %ERROR can be set by any action that allows the use of an error indicator. The CALLP operation can also set %ERROR.
Example:
Result
%SIZE :
The number of bytes that the element occupies is returned by the %SIZE function.
A named constant, data structure, array, field, literal, etc. can all be used as arguments.
%SIZE returns full length for a field with a null value.
For an array or multiple occurrence data structure, the elements or occurrences size is additionally considered if *ALL is given as the second option for %SIZE.
Syntax: %SIZE(variable)
%SIZE(array{:*ALL})
%SIZE(table{:*ALL})
%SIZE(multiple occurrence data structure{:*ALL})
Example:
Result
%TIMESTAMP :
To convert a string into a timestamp data type, use the %TIMESTAMP method.
Syntax: %TIMESTAMP (value : *ISO | *ISO0 )
The input value that we wish to convert to a timestamp is the first parameter in this case.
The second option, which informs us of the input string’s timestamp format, can also be mentioned.
Example:
Result
%FOUND:
If the most recent operation finds out a relevant or matching record, %FOUND returns ‘1’; however, an exact match is not assured.
In the event that no match is found, ‘0’ is returned.
Syntax: %FOUND{(file_name)}
Example:
%MAXARR:
%MAXARR returns the index of the maximum value in the array, or the subsection of the array identified by the start-element operand and the number-of-elements operand.
Syntax: %MAXARR(array {: start-index {:number-of-elements}})
Example:
Result
%MINARR:
%MINARR returns the index of the minimum value in the array, or the subsection of the array identified by the start-element operand and the number-of-elements operand.
Syntax: %MINARR(array {: start-index {:number-of-elements}})
Example:
Result
%STATUS:
The program or file status’s most recent value is returned by the %STATUS function. %)STATUS is set anytime there is a change in the status of any file or program, usually as a result of an error.
The most recent program or file status update is returned if %STATUS is used without the optional file_name parameter. If a file is specified, the value contained in the INFDS *STATUS field for the specified file is returned. It is not necessary to specify the INFDS for the file.
%STATUS starts with a return value of 00000 and is reset to 00000 before any operation with a ‘E’ extender specified begins.
Syntax: %STATUS{(file_name)}
Example:
%LEN:
You can set the current length of a variable-length field, find the maximum length of a varying-length expression, or retrieve the length of a variable expression using %LEN
A figurative constant cannot be the parameter.
Syntax: %LEN(expression) or %LEN(varying-length expression : *MAX)
Example:
Result
%REM :
When operands n and m are divided, the remainder is returned by %REM. Numerical values with zero places in decimals must be the two operands. If either operand is a packed, zoned, or binary numeric value, the result is packed numeric. An integer is the result if either operand has an integer numeric value.
If not, unsigned numeric is the outcome. Numerical operands that float are not permitted. The sign of the outcome and the dividend are the same.
Syntax: %REM(n:m)
Example:
Result
%INT:
The built-in %INT function converts the numeric expression’s value to an integer.
Syntax: %INT(NumericExpression)
Example:
Result
%MSG:
The second operand in the SND-MSG operation is %MSG. Other than for the SND-MSG operation, %MSG cannot be provided and does not return a value.
Sending the message is specified by %MSG.
The message ID is the first operand. It must be a character expression in the job CCSID. The message ID consists of seven characters. The operand’s remaining characters must be blank if its length exceeds 7. The message ID needs to be present in the message file at run-time.
The message file is the second operand. In the CCSID task, it needs to be a character expression. One of the following formats is possible for it:
- MYMSGF
- MYLIB/MYMSGF
- *LIBL/MYMSGF
There is an optional third operand. It specifies the replacement text for the message. It could be a data structure or a character value in the job CCSID
Syntax:
Example:
I can use the %MSG BiF to send that message to the job log. Before I can show that I am going to need to have a message file, and a message within it I can use.
%STR:
Null-terminated character strings, which are frequently used in C and C++ applications, can be created or utilized with the %STR symbol.
A value for a starting point must be the first parameter. (Any expression that starts with “%ADDR(DATA)” or “P+1” is acceptable as a basing pointer.) The second parameter, if specified, must be a numeric value with zero decimal positions.
If not specified, it takes the longest character variable definition provided by default.
The first parameter must point to storage that is at least as long as the length given by the second parameter.
Syntax: %STR(basing pointer{: max-length})(right-hand-side)
%STR(basing pointer : max-length)(left-hand-side)
Example:
I can use the %MSG BiF to send that message to the job log. Before I can show that I am going to need to have a message file, and a message within it I can use.
%OPEN:
When a file is given and opened, %OPEN returns ‘1’. When a file is opened by the RPG module at initialization or through an OPEN operation and hasn’t been closed since, it’s referred to be “open”.
The file is considered to be closed and %OPEN returns ‘0’ if it is dependent on an external indicator and that indicator was turned off during module initialization.
Syntax: %OPEN(file_name)
Example:
%UNS :
The expression’s value is converted to unsigned format using %UNS. Any decimal digits are truncated. An array index can be created by truncating the decimal places of a float or decimal value using %UNS.
If a character expression is used as the parameter
See Rules for converting character values to numeric values using built-in functions for the rules for character expressions for %DEC.
Floating point data cannot be used, such as ‘1.2E6’.
Floating point data is not allowed. In other words, when the numerical value is followed by an exponent (as in ‘1.2E6’) and E.
If invalid numeric data is found, an exception occurs with status code 105
Syntax: %UNS(numeric or character expression)
Example:
Result
%UNSH:
%UNSH and %UNS are equivalent, with the exception that when converting an expression to an integer type, half an adjustment is applied to the expression’s value if it is a decimal, float, or character value. No message is issued if half adjust cannot be performed.
Syntax: %UNS(numeric or character expression)
Example:
Result
%TLOOKUPxx
The current table element for the search table is set to the element that satisfies the condition if a value meets the specified condition; if not, the function returns the value *ON and sets the current table element for the alternate table to the same element.
*OFF is returned if no value fulfills the required criteria.
Any type is acceptable for the first two arguments, but they must be of the same type. They do not need to have the same length or number of decimal positions.
Unless arg or search-table is defined with ALTSEQ(*NONE), the ALTSEQ table is used.
Built-in functions %FOUND and %EQUAL are not set following a %LOOKUP operation.
%TLOOKUP
An exact match.
%TLOOKUPLT
The value that is closest to arg but less than arg.
%TLOOKUPLE
An exact match, or the value that is closest to arg but less than arg.
%TLOOKUPGT
The value that is closest to arg but greater than arg.
%TLOOKUPGE
An exact match, or the value that is closest to arg but greater than arg.
Syntax:
%TLOOKUP(arg : search-table {: alt-table})
%TLOOKUPLT(arg : search-table {: alt-table})
%TLOOKUPGE(arg : search-table {: alt-table})
%TLOOKUPGT(arg : search-table {: alt-table})
%TLOOKUPLE(arg : search-table {: alt-table})
Example:
Result
%TARGET:
The third operand in the SND-MSG operation is %TARGET. Other than for the SND-MSG operation, %TARGET cannot be provided and does not return a value.
%TARGET specifies the target program or procedure for the message.
*SELF may be used as the first operand. This is the default for an informational message. The current procedure receives the message.
*CALLER. This is the default for an escape message. The message is sent to the caller of the current procedure.
The name of a program or procedure on the program stack. It has to be a CCSID character value.
The second operand is the offset on the program stack. It is optional. If it is not specified, it defaults to zero. It must be a numeric value with zero decimal positions.
The value cannot be negative.
Example:
%SUBARR:
Built-in function %SUBARR returns a section of the specified array starting at start-index. The optional number-of-elements parameter specifies how many elements will be returned. The number-of-elements defaults to the remaining value in the array if it is not supplied.
%SUBARR requires an array as its first parameter. That is, an array-defined standalone field, data structure, or subfield. The first parameter must not be a table name or procedure call.
There must be a numeric value with zero decimal places for the start-index argument. A float numeric value is not allowed. The value must be less than or equal to the array’s element count and higher than or equal to 1.
A integer value with zero decimal places must be entered for the optional number-of-elements argument.
Syntax: %SUBARR(array:start-index{:number-of-elements})
Example:
Result
%SHTDN :
%SHTDN returns ‘1’ if the system operator has requested shutdown; otherwise, it returns ‘0’.
Syntax: %SHTDN
Example:
Result
%FIELDS:
A file can be partially updated by using the %FIELDS function. To put it another way, we might just need to edit one or two fields in a file. For that we use this funtion.
We specify the name of the field we want to edit in the file in the %FIELDS argument. Only the mentioned fields are updated.
Syntax: %FIELDS(name{:name…})
Example:
Result
Before:
After:
%PARMS:
The number of parameters given to the procedure where %PARMS is used is returned by %PARMS. *PARMS and %PARMS are the same for the main procedure.
Example:
Result
%GRAPH:
%GRAPH returns a graphic value after converting the expression’s value from character, graphic, or UCS-2. If the parameter varies in length, the outcome will also vary in length.
The CCSID of the resulting expression is indicated by the second parameter, ccsid, which is optional. Control keyword CCSID(*GRAPH) specifies the default graphic CCSID of the module, which is the default CCSID by default.
The built-in %GRAPH is prohibited if CCSID(*GRAPH: *IGNORE) is mentioned in the control specification or presumed for the module.
Syntax: %GRAPH(char-expr | graph-expr | UCS-2-expr { : ccsid })
Example:
%INTH:
%INTH and %INT are equivalent, with except that when converting an expression to an integer type, half of the expression’s value is adjusted if it is a decimal, float, or character value. No message is issued if half adjust cannot be performed.
Syntax: %INTH(numeric or character expression)
Example:
Result
Operation Codes and Extenders
Definition:
Opcode extenders in IBM i are like modifiers for commands in programming. They help you specify details or customize the behavior of an operation, making it more flexible and tailored to your specific needs in the program you’re writing.
Types of Opcode extenders
Opcode extenders | Description |
---|---|
A | This extension is utilized on the DUMP operation to ensure that it is always executed regardless of the DEBUG option set on the H specification. |
H | This extension is used to half adjust (round) the result of a numeric operation. |
N |
|
P | Pads the result field with blanks. |
D |
|
T | Denotes a time field. |
Z | Refers to a timestamp field. |
M | Specifies default precision rules. |
R | Refers to “Result Decimal Position” precision rules. |
E | Handles error conditions. |
Uses of Opcode extenders
- For Assigning values.
- For Arithmetic operations.
- For Strings operations.
- For date/time/timestamp operations.
- For File operations
Opcodes extenders for Assigning values.
We have opcode extenders that are used while assigning numeric and string values. Below are the definitions of the work variables that we are using to perform operations using opcode.
- Eval(H): Half adjust (round) of the numeric value while evaluating a variable or parameter.
At line 31, once the eval opcode executes, it will add the values of a and b (i.e., 10.25 and 10.20) and assign a 20.45 value to the Result2 variable.
At line 34, once the eval opcode executes, it will add the values of a and b (i.e., 10.25 and 10.20) and assign a 20.4 value to the Result3 variable as it has only one decimal.
At line 37, once the eval opcode executes with Half Extender, it will add the values of a and b (i.e., 10.25 and 10.20) and assign a 20.5 value to the Result variable by rounding the value from 20.45 to 20.5. - Move(P) & Movel(P): Pad the string value with blank while moving from one variable to another.
At line 41, once the move opcode executes, it will move the value from A1 (‘AAAAA’) to B2(‘BBBBBBBBBB’) and assign the ‘BBBBBAAAAA’ value to the B2 variable.
At line 45, once the move opcode with P extender executes, it will move the value from A1 (‘AAAAA’) to B2(‘BBBBBBBBBB’) and assign the ‘ AAAAA’ value to the B2 variable.
At line 49, once the Movel opcode executes, it will move the value from A1 (‘AAAAA’) to B2(‘BBBBBBBBBB’) and assign the ‘AAAAABBBBB’ value to the B2 variable.
At line 53, once the Movel opcode with P extenders executes, it will move the value from A1 (‘AAAAA’) to B2(‘BBBBBBBBBB’) and assign the ‘AAAAA ’ value to the B2 variable. - Eval(M): It evaluates the default decimal value in a variable.
At line 57, once the Eval opcode with M extender executes, it will evaluate the value 2.80000 to the Result4.
- Eval(R): It evaluates the result decimal position precision value in a variable.
At line 57, once the Eval opcode with R extender executes, it will evaluate the value 2.85714 to the Result4.
Opcodes extenders for Arithmetic operations.
We have opcode extenders that are used while performing arithmetic operations. Below are the definitions of the work variables that we are using to perform operations using opcode.
- Add(H): Half adjust (round) of the numeric value while adding the values of the variables.
At line 64, once the Add opcode executes, it will add the values of a and b (i.e., 10.25 and 10.20) and assign a 20.45 value to the Result2 variable.
At line 66, once the Add opcode executes with Half Extender, it will add the values of a and b (i.e., 10.25 and 10.20) and assign a 20.5 value to the Result variable by rounding the value from 20.45 to 20.5.
- Z-Add(H): Half adjust (round) of the numeric value while adding zero to factor 2.
At line 72, once the Z-Add opcode executes with Half Extender, it will add the value of b and Result (i.e., 10.20 and 0) and assign a 10.2 value to the Result variable by rounding the value from 10.20 to 10.2.
Note: Result value will automatically change from 50 to zero as per Z-ADD opcode, it will convert the Result value to zero and then add with factor-2.
0 + Factor 2 (numeric) Result field
- Sub(H): Half adjust (round) of the numeric value while subtracting the values from one variable to another.
At line 78, once the Sub opcode executes, it will subtract the value from e to f (i.e., 20.55 and 10.20) and assign a 10.35 value to the Result2 variable.
At line 82, once the Sub opcode executes with Half extender, it will subtract the value from e to f (i.e., 20.55 and 10.20) and assign a 10.4 value to the Result variable by rounding the value from 10.35 to 10.4.
- Z-Sub(H): Half adjust (round) of the numeric value while subtracting factor-2 from 0.
At line 88, once the Z-Sub opcode executes with Half extender, it will subtract the value from Result to b (i.e., 0 and 10.20) and assign –10.2 value to the Result variable by rounding off the value from 10.20 to 10.2.
Note: Result value will automatically change from 50 to zero as per Z-SUB opcode, it will convert the Result value to zero and then subtract it to factor-2.
0 – Factor 2 (numeric) – Result field
- MULT(H): Half adjust (round) of the numeric value while multiplying the value of variables.
At line 93, once the Mult opcode executes, it will multiply the value of a and b (i.e., 10.25 and 10.20) and assign a 104.55 value to the Result2 variable.
At line 96, once the Mult opcode executes with Half extender, it will multiply the value of a and b (i.e., 10.25 and 10.20) and assign 104.6 value to the Result variable by rounding the value from 104.55 to 104.6.
- DUMP(A): It is used to perform the dump operation to ensure the operation occurs regardless of the debug option set in the H specification.
At line 44, once the Eval opcode executes, it will try to divide the Num1 by Num2 (i.e., 100 and 0) and assign the default value 1 to Result as 100/0 is not possible.
Opcodes extenders for Strings operations.
We have opcode extenders that are used while performing string operations. Below are the definitions of the work variables that we are using to perform operations using opcode.
- SUBST(E P): Error handling or padding with blank while substring the string variable.
At line 35, once the Subst opcode executes, it will substring the variable Target (‘XXXXXXXX’) with String1 (‘TEST123’) from starting position T (5) till length (3) and substring the value of target from ‘XXXXXXXX’ to ‘T12XXXXX’.
At line 37, once the Subst opcode with E extender executes, it will try to substring the variable Target (‘XXXXXXXX’) with String1 (‘TEST123’) from starting position X (22) till length (3) but display the ‘Error’ message as the 22 index is not present in Target variable.
At line 43, once the Subst opcode with P extender executes, it will substring the variable Target (‘XXXXXXXX’) with String1 (‘TEST123’) from starting position T (5) till length (3) and substring the value of target from ‘XXXXXXXX’ to ‘T12 ’.
- SCAN(E): Error handling while searching the string.
At line 46, once the Scan opcode executes, it will try to search the blank in the variable String (‘Search String’) from starting position K (5) and 7 will assign it to the Pos variable.
At line 46, once the Scan opcode with E extender executes, it will try to search the blank in the variable String (‘Search String’) from starting position X (22) but display the ‘Error’ message as the 22 index is not present in a String variable.
- XLATE(E P): Error handling or padding with blank while translating from character to character by the protocol specified in factor-1.
At line 55, once the Xlate opcode executes, it will try to translate the Chgcase2 (‘rpg dept’) variable with Result2 (‘XXXXXXXXXXXXXXX’) by the protocol specified in factor-1 and assign the new value ‘RPG DEPT XXXXX‘ to the Result2.
At line 60, once the Xlate opcode with P extender executes, it will try to translate the Chgcase2 (‘rpg dept’) variable with Result2 (‘XXXXXXXXXXXXXXX’) by the protocol specified in factor-1 and assign the new value ‘RPG DEPT ‘ to the Result2 while padding the ‘XXXXX’ with blank of Result2.
At line 68, once the Xlate opcode with E extender executes, it will try to translate the Chgcase2 (‘rpg dept’) variable with Result2 (‘XXXXXXXXXXXXXXX’) from starting position X (22) by the protocol specified in factor-1 but display the ‘Error’ message as the 22 index is not present in Chgcase2 variable.
- CHECK(E): Error handling while checking the non-occurrence of a character in a string.
At line 73, once the Check opcode executes, it will try to check the factor-1 (‘ABCD) in the factor-2 variable Substring (‘AABC1ABD2AV3A’) and 5 will assign it to the Pos variable.
At line 76, once the Check opcode executes, it will try to check the factor-1 (‘ABCD) in factor-2 variable Substring (‘AABC1ABD2AV3A’) from starting position T (5) and 20 will assign to Pos variable.
At line 78, once the Check opcode with E extender executes, it will try to check the factor-1 (‘ABCD) in factor-2 variable Substring (‘AABC1ABD2AV3A’) from starting position X (22) but display the ‘Error’ message as the 22 index is not present in substring variable.
Opcodes extenders for date/time/timestamp operations.
We have opcode extenders that are used while performing date/time/timestamp operations. Below are the definitions of the work variables that we are using to perform operations using opcode.
- Test(EDTZ): Validate the date, time or timestamp.
At line 29, once the Test opcode with Z extender executes, it will try to test the timestamp Char_Tstmp (‘19960723140856834000’) with *ISO format and turn off the error indicator 18 as the Char_Tstmp1 is the correct timestamp.
At line 30, once the Test opcode with Z extender executes, it will try to test the timestamp Char_Tstmp1 (‘190723140856834000’) with *ISO format and turn on the error indicator 18 as the Char_Tstmp1 is not the correct timestamp.
At line 31, once the Test opcode with Z and E extender executes, it will try to test the timestamp Char_Tstmp1 (‘190723140856834000’) with *ISO format and display the message ‘Invalid Fmt’ as the Char_Tstmp1 is not correct timestamp.
At line 36, once the Test opcode with D extender executes, it will try to test the date Char_Date (‘041596’) with *MDY format and turn off the error indicator 19 as the Char_Date is the correct date.
At line 37, once the Test opcode with D and E extender executes, it will try to test the date Num_Date (‘910921’) with *DMY format and display the message ‘Invalid Fmt’ as the Num_Date is in YYMMDD format, but we are checking in*DMY format.
At line 41, once the Test opcode with E and T extender executes, it will try to test the time Char_Time (‘13:05 PM’) with *USA format and it won’t give any error as the format of Char_Time matches with the *USA format.
Opcodes extenders for file operations.
We have an ‘N’ opcode extender that is used to make the record not locked while reading. Before is the simple example of an N opcode extender.
On line 9, we have declared one file PIOFILE in update mode, and on line number 10, we are reading the same file 10 times from 1 to 10. Once line 21 executes with the N opcode extender, the record is not locked while reading operation and if any update/delete operation is performed then it will execute without any error.
Indicators
- Indicators defined on the RPG/400 specifications.
- Indicators not defined on the RPG/400 specifications.
1. Indicators defined on the RPG/400 specifications.
1. Indicators defined as variable in RPGLE program –
Fix-format syntax for standalone indicator:
Name | Declaration Type | To / Length Internal | Data Type |
---|---|---|---|
Name-of-Indicator | S | 1 | N |
Declaration type ‘S’ can be ignored if it is not a standalone variable.
Free format syntax:
dcl-s Name-of-Indicator ind;
Code Examples –
Fix-format:
In above screenshot –
On line 17.00: We are turning on isExist indicator if record is found on line 16.00.
On line 21.00: We have used isExist indicator, if record was found in EMPPF file and also found in EMPDEPT file then processing the file on line 22.00.
Free format:
2. Overflow indicator –
The PRINTER file lines that will be produced when there is an overflow are determined by the overflow indicator specified by the OFLIND keyword.
OFLIND keyword only works with PRINTER devices.
Automatic page ejection upon overflow (default overflow processing) takes place in the absence of the OFLIND keyword.
Syntax:
OFLIND(indicator-name);
In OFLIND, we can use below valid indicators –
*INOA to *INOF, *INOV:
These indicators we can use in a program described printer file to handle conditions when overflow line is reached. These indicators not valid for externally described files.
*IN01 to *IN99:
These indicators we can use, when the overflow line is reached or passed during a space or skip operation.
Name:
This can be a variable name which has indicator type. We can use this indicator when the overflow line is reached. The program must handle the overflow condition.
It has same behaviour as for indicators *IN01 to *IN99.
Code Examples –
Fix-format:
In above screenshot, there is an externally described printer file CUSREPORT declared with OFLIND keyword which has indicator *IN99
*IN99 will be turn on when overflow occurs in respective printer files CUSREPORT.
In above screenshot, we are handling overflow with *IN99 indicator. When overflow occurs, it will print the heading again.
Free format:
3. Display file indicator integration using address of indicators –
By assigning variables to the address of indicators, we can utilize readable names instead of indicators in RPG programs.
To do this –
- There should be INDARA keyword at file level in display file. It provides the functionality to use indicator data structure in RPG program.
- Declare display file in RPG program with INDDS keyword with indicator data structure name.
- Declare a pointer variable by initializing with address of indicators.
- Declare indicator data structure with based on pointer variable.
- Now, we can use subfields of indicator data structure in RPG program.
Code Examples –
INDARA keyword declared at file level in display file –
RPGLE Program declaration to use indicator data structure –
Line 0003.00 is a display file declaration, we have used INDDS keyword to give name of the indicator data structure which is indicatorDs in this example.
Line 4.00 is a declaration of pointer variable initialized with the address of indicators.
Line 5.00 is an indicator data structure which is based on pointer variable declared in line 4.00.
Line 6.00 is a subfield of indicatorDs, it has indicator data type, it relies on position 5, so it can be used in place of *IN05.
In Line 31.00, we have a variable ‘previous’ which is a subfield of indicator data structure, it is pointing to the address of indicator ‘*IN12’.
So, when previous will be turned on, then *IN12 will also turn on automatically.
4. Control Level Indicators (L1-L9)
The control level indicators (L1 to L9) are used to manage program flow, especially within loops and conditional statements. These indicators are set and checked during the execution of the program.
Certainly! Here’s an example that demonstrates how you can use control level indicators with physical and logical files in RPG on an IBM i system. In this example, we’ll create a simple program that reads records from a physical file, applies some conditions using control level indicators, and writes the selected records to a logical file.
Assuming you have two files:
There are 2 logical files EMPIOREC and EMPIOTIM.
Here’s an RPG program that increase the count of the variable when level break occurs.
- A comment indicates that when a level break occurs on `L2` (PIO_DIVSON), it should add 1 to the `PIOCNT` variable.
- The line ‘L2 PIOCNT ADD 1 PIOCNT 40’ suggests that if a level break occurs on ‘L2’, it will add 1 to the ‘PIOCNT’ variable.
5. Function Key Indicator
Function keys are specified in the DDS with the CFxx (command function) or CAxx (command attention) keyword. For example, the keyword CF01 allows function key 1 to be used. When you press function key 1, function key indicator KA is set on in the RPG program. If you specify the function key as CF01 (99), both function key indicator KA and indicator 99 are set on in the RPG program. If the work-station user presses a function key that is not specified in the DDS, the IBM® i system informs the user that an incorrect key was pressed.
Certainly! Below is an example RPGLE program and DDS source code that follows the specified requirements. In this example, the program reads the display file, and when the user presses Function Key F1 or F2, it sets the corresponding indicators in the RPG program. If the user presses an incorrect key, an error message is displayed.
RPGLE code.
DDS code
In this example, the display file (MyDisplay) has two input fields (FIELD1 and FIELD2). The indicators KA and KB are associated with Function Keys F1 and F2, respectively. The program (MyProgram) reads the display file and checks the values of KA and KB to determine which function key was pressed. If an incorrect key is pressed, an error message is displayed. Adjust the logic inside the ProcessF1 and ProcessF2 subroutines based on your specific requirements for handling each function key.
Below is the table for the function key indicator with its corresponding key.
Function Key Indicator | Corresponding Function Key | Function Key Indicator | Corresponding Function Key |
---|---|---|---|
KA | 1 | KM | 13 |
KB | 2 | >KN | 14 |
KC | 3 | KP | 15 |
KD | 4 | KQ | 16 |
KE | 5 | KR | 17 |
KF | 6 | KS | >18</td |
KG | 7 | KT | 19 |
KH | 8 | KU | 20 |
KI | 9 | KV | 21 |
KJ | 10 | KW | 22 |
KK | 11 | KX | 23 |
KL | 12 | KY | 24 |
6. Halt Indicator (H1-H9)
The Halt indicators are used to handle the error while running of a program. It can be used with record identifying indicators, field indicators, or resulting indicators.
Certainly! In RPG II, you can use the H1 indicator as a halt indicator. Below is a simple example:
The H1 indicator is used as a halt indicator. When H1 is turned on, the program will stop processing.
The program goes through the usual sequence of input, processing, and output operations.
The PROCESSDATA subroutine checks the condition (*IN99) and increments a counter (NUMOFRECORDS) for demonstration purposes. If the condition is met (in this case, *IN99 is on), the program moves a message to the MSG field, displays it, and sets *INLR to halt the program.
2. Indicators not defined on the RPG/400 specifications.
- Internal IndicatorsThe internal indicators, often referred to as “I” indicators, are special variables used to control the flow of a program and handle various operations and conditions. These indicators are used for decision-making, error handling, and controlling the logic of a program.
- First Page Indicator (1P): – Definition: The first page (1P) indicator is set on by the RPG IV program when the program starts running and is set off by the RPG IV program after detail time output.-Usage: The first record will be processed after detail time output. The 1P indicator can be used to condition heading or detail records that are to be written at 1P time.
- Last Record Indicator (LR): – Definition: The Last Record Indicator (LR) is used to identify the last record in a report or file. – Usage: Typically, LR is set to *ON for the last record in a report or file to indicate the end of the report or file. Example:
or
or
In this example, the LR indicator is specified in the printer file’s output specification. It is automatically set to *ON for the last record in the output.
- Matching Record Indicator (MR): – Definition: The Matching Record Indicator (MR) is used to indicate that two or more fields in a record match specified criterion.– Usage: MR is often used in program logic to identify matching records based on specified conditions.Example:
Three files are used in matching records. All the files have three match fields specified, and all use the same values (M1, M2, M3) to indicate which fields must match. The MR indicator is set on only if all three match fields in either of the files EMPMAS and DEPTMS are the same as all three fields from the WEEKRC file.
The three match fields in each file are combined and treated as one match field organized in the following descending sequence:
DIVSON
M3
DEPT
M2
EMPLNO
M1 - Return Indicator (RT):– Definition: The Return Indicator (RI) is used to determine whether a subroutine or called program has executed successfully and returned a result.– Usage: The test to determine if RT is on is made after the test for the status of LR and before the next record is read. If RT is on, control returns to the calling program. RT is set off when the program is called again.
- External Indicators used as JOB Indicators –There are 8 external indicators, U1 through U8 which can be set in a CL program or in an RPGLE program.In a CL program, they can be set by the SWS (switch-setting) parameter on the CL commands CHGJOB (Change Job) or CRTJOBD (Create Job Description).In an RPGLE program, they can be set by direct assignment or using any assignment opcodes.
Code examples –
In above screenshot, it is a CL program logic.
On line 2, Indicator U8 is set to turn on by SWS parameter on CL command CHGJOB.
In SWS parameter of CL command CHGJOB, we can set 8 indicators (U1 through U8).
- Type ‘1’ on corresponding position to turn on the indicator.
- Type ‘0’ on corresponding position to turn off the indicator.
- Type ‘X’ on corresponding position for no change of the indicator.
On line 3, it is calling GETCUSTDTL program. In this program we can handle the program flow by conditioning with these indicators.
Fix format:
Above is the screenshot for the logic of GETCUSTDTL program, which is handling *INU8 indicator. If it is turned on, then process only ENG customers otherwise process all customer.
Free format:
CL program example to turn on U8 indicator by SWS parameter of CRTJOBD CL command.
In RPGLE program, job indicators can be set and use in other calling/called program as well to maintain the program flow.
It can be set by any assignment opcodes like Eval, Move.
Fix format:
Free format:
Directives
Complier Directives
Compiler Directive is an instruction or direction given to the compiler –
- To perform some specific tasks during compilation.
- To generate customize compiler listing report after compilation.
Compiler Directives can be used for many purposes, like :-
- To control the spacing of the compiler listing.
- To include source statement from another source member.
- To do a free form calculation in our RPGLE/SQLRPGLE program.
- To control the source records selection/omission based on some condition.
- To control the heading information in compiler listing.
Compiler directives are divided into two types:
- Compiler directive statements. For example- /TITLE, /EJECT, /COPY and /INCLUDE etc.
- Conditional compiler directives, these allow us to select or omit the source line. For example- /IF, /ELSEIF, /ENDIF, /ELSE , /EOF etc.
Let’s go through the compiler directives one by one:
A. /TITLE
It is used to add heading information in the compiler listing. Its position on the source code is 7-12 in fixed format. From 14-100 we can give the information about the title.
Few important points:
- We can use more than one /TITLE statement in one program.
- Each /TITLE statement provides heading information for the segment of compiler listing until another /TITLE statement is encountered.
- The /TITLE statement is printed in addition to compiler heading information.
- Each /TITLE statement is printed on a new page.
Example:
In the below example, we have used TITLE directive and along with this, some information of that title, so in the compiler listing it will show this Title information and the last Title which is written as Main code in the example will be listed till last in the compiler listing.
After Compilation:
As we can see the title heading are listed in the compiler listing and the last heading MAIN CODE is listed till last as it was the last heading with directive /TITLE.
B. /EJECT
It is used to make the compiler add new pages in the compiler listing. The new pages will be added from the line where the /EJECT is specified in the code or source.
Its position on the source code is 7-12 in fixed format.
Example:
In the below example we have used /EJECT.
After Compilation:
After /EJECT the compiler will add a new page for the source listing from the line where /EJECT is used in the source code.
C. /FREE and /END-FREE
With the help of this, we can write the codes in free format. For this, we need to enclose our code between /FREE and /END-FREE.
It’s position on the source code is 7-11 in fixed format.
NOTE: It is no longer needed , it is required only if your IBM i does not have the PTF for “free format definition” RPG, that was released along with IBM i 7.1 TR7.
Example:
In the below example, we can see how we can use /Free and /End-Free directive in our code.
Here we can see we have first used the fixed format then if we want to do code in free format we can use this directive.
D. /COPY And /INCLUDE
Both /COPY and /INCLUDE is used to add source records to the current program from other source members. Both directives have the same purpose and syntax, but they are handled differently by SQL preprocessor.
- The /COPY directive is expanded by the preprocessor. The copied file or source can contain embedded SQL or host variables.
- The /INCLUDE directive is not expanded by the preprocessor. The included file or source cannot contain embedded SQL or host variables.
/COPY and /INCLUDE files can be either physical files or IFS files. Its position on the source code is 7-12 in fixed format.
Syntax:
To specify a physical file, the library, file name, and member name, we can use any one of the below formats:
- Library name/source filename, member name.
Example- /COPY PIOLIB/QRPGLESRC,COPY_SRC - Source filename, member name.
Example- /COPY QRPGLESRC,COPY_SRC - Member name.
Example- /COPY COPY_SRC
Important point regarding syntax:
- The member’s name must be specified.
- If the source file is not specified, then QRPGLESRC is assumed.
- If the Library is not specified, then library taken from the *LIBL (Library list).
Example: In the below example we have used a copy book.
After compilation:
When we compile the above program, in the compiler listing the /COPY is replaced by the actual source which we have written in the copy book source.
In the compiler listing
E. /SPACE
This directive is used to control the line spacing within the source section of compiler listing.
F. /SET And /RESTORE
/SET directive is used to temporarily set a new default value for definitions and to reverse the effect of /SET, we can use /RESTORE.
With /SET directive, we can use the following keywords:
- CCSID(*Char: ccsid)
Syntax : CCSID(*Char: *JOBRUN or *JOBRUNMIX or *UTF8 or *HEX or number). - CCSID(*GRAPH: ccsid)
Syntax : CCSID(*GRAPH: *JOBRUN or *HEX or *SRC or *IGNORE or number). - CCSID(*UCS2: ccsid)
Syntax : CCSID(*UCS2: *UTF16 or number). - DATFMT(format)
Syntax : DATFMT( fmt{separator}). - TIMFMT(format)
Syntax : TIMFMT( fmt{separator}).
Efficient way of using these directives:
- We can specify the SET directive in a copy file so that all modules that include the copy file use the same values for the time and date formats and the CCSIDs.
- We can also code the /SET directive prior to the /COPY or /INCLUDE directive, and then code the /RESTORE directive after the /COPY or /INCLUDE directive to restore the defaults to the values that were previously in effect before the /SET directive.
Some important point :
- We can nest /SET directives.
- The keywords specified on a /RESTORE directive do not have to exactly match the keywords specified on the previous /SET directive.
- A /RESTORE directive can restore some or all the values set by any previous /SET directives.
Example:
In the below example, we have used /SET directive to set the ccsid of *char and used /RESTORE to reset the CCSID
After Compilation:
We got the below result, as we have declared the string2 variable after setting the ccsid of *char using /SET and just after declaring string2 variable we have restored the ccsid using /RESTORE directive. So we got the below result for string2.
String1 is declared before the setting ccsid and string3 is after resetting the ccsid ,so we get the character values of the string1 and string3.
G. /IF, /ELSEIF, /ELSE, /ENDIF, /DEFINE and /UNDEFINE
- /IF compiler directive is used to do the conditional compilation.
- /IF can be followed by one or more /ELSEIF, followed by an optional /ELSE, and finished with a /ENDIF.
- If the condition expression is true, source lines following the /IF directive are included in the current source to be read by the compiler. Otherwise, lines are excluded until the next /ELSEIF, /ELSE or /ENDIF in the same /IF group.
- /DEFINE directive “Set On” a condition and /UNDEFINE directive “Set Off” a condition.
- Basically, it is used to define an element that will be used as a condition element for /IF, /ELSEIF directive.
Entry position of /IF :
7-9 = /IF
11-80 = conditional expressionEntry position of /ELSEIF :
7-13 = /ELSEIF
15-80 = conditional expressionEntry position of /ELSE :
7-11 = /ELSE - The /ENDIF compiler directive is used to end the /IF, /ELSEIF or /ELSE group.
Entry position of /ENDIF :
7-12 = /ENDIF
Example:
The below example contains the usage of /IF,/ENDIF and /DEFINE directives.
In the below example ,we have set a condition ON using /DEFINE which is DIVIDE and then using /IF checked if the DIVIDE condition is set ON, then we will add copy book CALCDIV, otherwise not.
After Compilation:
As in the /IF the DIVIDE is defined using /DEFINE means it is ON, so in our source listing compiler will add the copy book in the source.
H. /EOF
By using this directive, we are instructing the compiler to ignore any source lines that come after this directive.
Example:
In the below example we can see how we used /EOF and when we compile this the compiler will not compile the source after the line containing /EOF.
Limitations:
There are some points we need to take care of, while using the directives.
- The compiler directive statements must precede any compile-time array or table records, translation records, and alternate collating sequence records.
- No directive can be specified within a single free-form calculation statement.
- The /IF, /ELSEIF, /ELSE, and /ENDIF directives can be specified within a single free-form control, file, definition, or procedure statement. No other directives can be specified within these statements.
- Within a free-form statement, when a line begins with what appears to be a directive that is not allowed within that statement, it is interpreted as a slash followed by a name.
- The special directive **FREE can only appear in column 1 of the first line of the source.
File Handling
Types of files:
Multiple types of file exist in an IBM i series native filesystem that we can use in RPGLE programs/modules.
- Database files:
- It includes file that can contain data in tabular form.
- Physical and logical files are database files.
- In case of database file, the file type on F-Spec can be.
- I for using file in Input mode for reading records.
- O for using file in output mode for writing records to the file
- U for opening file in update mode for updating existing records.
- We can also use, file addition with input and update mode to add records to the file.
- In free-format, we use usage keyword to designate the mode in which it will be used in the program. The possible values are.
- *Input for using file in Input mode for reading records.
- *Output for using file in output mode for writing records to the file
- *Update for opening file in update mode for updating existing records.
- *Delete for deleting the records from the file.
- You can use *input with *output, to read and write records without update. It is same as file addition that we use in fixed format.
Below are some examples.
Fixed format
FPRODUCTS IF E DISK
Free format
dcl-f PRODUCTS usage(*input);
Fixed format
FPRODUCTS IF A E DISK
Free format
dcl-f PRODUCTS usage(*input:*output);
Fixed format
FPRODUCTS UF E DISK
Free format
dcl-f PRODUCTS usage(*delete);
- Workstation Files
- A WORKSTN file is an externally described display-device file that is used to display information and takes user input.
- The most used externally described WORKSTN file is a display file.
- The file type on F-Spec for WORKSTN file is C, means combined.
Below is an example.
Fixed format
FORDERDSPF CF E WORKSTN indds(IndDs) F sfile(SFLORD:S1RRN)
Free format
dcl-f ORDERDSPF workstn indds(IndDs) sfile(SFLORD:S1RRN) ;
- Printer files
- A printer file is a virtual file having data specifications used for later output to a printer.
- A printer file can only be used as output type and O needs to be specified in the F-Spec
Below is an example.
Fixed format
FREPORTDN O E PRINTER
Free format
dcl-f REPORTDN printer;
Multi-member Physical files:
A physical file can have multiple members. By default, when a PF is created it has only one member by the same name as the file. We can use the ADDPFM command to add a new member to the PF.
Below are a few useful keywords that help us in dealing with multi-member files easier.
- EXTMBR: This RPGLE keyword is used on an F-spec and describes which member of the file will be opened at program initialization. You can specify a member name, or ‘*ALL’, or ‘*FIRST'(default). The member-name should be in upper case. We can also use variable names for the member names but one of the below considerations should be kept in mind for the variable declaration.
- Use the INZ keyword to initialize the member-name on the D specification.
- Passing the value in as an entry parameter
- Using a program-global variable that is set by another module.
- Below is an example of the keyword with *ALL.
Fixed formatFPRODUCTS IF E DISK EXTMBR('*ALL')
Free format
dcl-f PRODUCTS usage(*input) extmbr(*ALL');
In the above example, all the members are read sequentially. In other words, when all the records from the first member have been read, the program will start reading then the records in the second member.
- Consider another example of a file FRUITS having multiple members. For each member we will have to read the file and do some processing. So, we can use the keyword with member-name as a literal.
Fixed formatFPRODUCTS IF E DISK EXTMBR('MANGO’)
Free format
dcl-f PRODUCTS usage(*input) extmbr(‘MANGO’);
- Sometimes, we have a use case where the member-name is not constant and is changed based upon some conditions. In that case, we can use a variable for the member-name.
Fixed formatFPRODUCTS IF E DISK EXTMBR(MBRNAME)
Free format
dcl-f PRODUCTS usage(*input) extmbr(MBRNAME);
As the file will be opened at program initialization, the MBRNAME must be populated in upper-case before that. You can declare the variable and initialise it with a default value or the variable can be received as an *entry parameter.
- There is another use-case where we have a dynamic member name, let’s suppose with today’s date. E.g OR20240101 is the member-name for a multi-member order file having members for each date.To read the member as per today’s date, we can use below logic. We use the USROPN keyword and initialize the variable later in our program, but, before doing an open on the file.
dcl-f PRODUCTS usage(*input) extmbr(MBRNAME) usropn; dcl-s MBRNAME char(10); MBRNAME = ‘OR’ + %char(%Date():*iso0); Open PRODUCTS; Setll *loval PRODUCTS; Read PRODUCTS; Dow not %eof(PRODUCTS); Validate(); Read PRODUCTS; Enddo; Close PRODUCTS; *inlr = *on;
- EXTFILE: This F-spec keyword is used to specify the file and library which will be opened at program initialization. Below are the possible values for the keyword. The values must be in upper-case.
- filename
- libname/filename
- *LIBL/filename
- *EXTDESC
Fixed format
Finput if f 10 disk extfile(‘MYLIB/IN2024’)
Free format
dcl-f input usage(*input) extfile(‘MYLIB/IN2024’);
If a variable name is used, it must be set before the file is opened. For files that are opened automatically during the initialization part of the cycle, the same considerations apply as EXTMBR.
The example above shows how you can call the file any name you would like, in this case, it is input. The EXTFILE tells the program where to find the file, the library name is optional. In this case, the file is in MYLIB. This could be considered a replacement for the CL command OVRDBF.
- EXTNAME: This F-Spec keyword is used with data structure declaration to fetch the field descriptions of the file specified. Below are the examples:
Fixed formatD recOrd E DS extname(‘ORDHDR’)
Free format
dcl-ds record extname(‘ORDHDR’);
File read Op-Codes:
- SETLL: SETLL sets the file pointer at the lower limit of the record entry where the key field/RRN value is greater than or equal to the factor-1 search argument value. After positioning the file pointer, we can go for any file operation e.g. READ, READP,READPE, READE which are discussed further down the line.
- In factor-1 we can use figurative constant *LOVAL, *HIVAL, *START, *END or we can use RRN VALUE, KEY VALUE, KEY LIST or KEY DS.
- To determine if the record having the key field/RRN value exactly same as the search argument value in factor-1 is found, we can use %EQUAL BIF.
Fixed format
C 'MONKEY' SETLL RECORD
Free format
Setll ‘MONKEY’ RECORD;
- SETGT: SETGT sets the file pointer at the higher limit of the record entry where the key field/RRN value is greater than the factor-1 search argument value. After positioning the file pointer, we can go for any file operation e.g. READ, READP,READPE, READE which are discussed further down the line.
- In factor-1 we can use figurative constant *LOVAL, *HIVAL, *START, *END or we can use RRN VALUE, KEY VALUE, KEY LIST or KEY DS.
- To determine if the record having the key field/RRN value exactly same as the search argument value in factor-1 is found, we can use %EQUAL BIF.
Fixed format
C 'MONKEY' SETGT RECORD
Free format
Setgt ‘MONKEY’ RECORD;
- READ: This opcode is used to read the records from a database file. The record is read based on the pointer set by SETXX opcodes, once the record is read it moves the pointer to next available record. This generally is used with *LOVAL/*HIVAL and SETXX opcodes. E.g. SETLL sets the file pointer at the first occurrence of the record where the key field/RRN value is greater than or equal to the factor-1 search argument value. After positioning the file pointer, we can go for any file operation like READ.
- We can also use a data structure as a resultant field to retrieve the values in it.
- If a file is declared in update mode, the read opcode takes an exclusive lock on the record which can cause issues if multiple programs are using the file at the same time. To circumvent this, we can use READ opcode with (n) extender, to read the file with no lock.
To monitor read opcode for error we can also use the (e) extender and check for errors on the next line using %error() built-in function.
Fixed format syntax:
Resulting Indicators Factor 1 Opcode Factor 2 Result Field HI LO EQ READ(N|E) File or record format name Data structure to hold the result Error End-of-file condition indicator Free format Syntax:
Read(n|e) file/record format [Data Structure]
- READE: This opcode is used to read an exact match of the key specified in the factor 1. If multiple records for an exact criterion are to be read, READE can be used with SETXX opcodes with factor 1.
- If the matching criteria is not found the EOF condition is reached.
- To handle exceptions, operation extender (e) can be used.
- READP: It is generally used to read the file in reverse order. READP moves the pointer to the previous record and reads the record and again moves the pointer to next previous position. If there are no more records it sets EOF indicator to *ON. It is usually used with SETLL and *HIVAL.
0001.00 FORDERS IF E K DISK 240105 0002.00 C *HIVAL SETLL ORDERS 240105 0003.00 C READP ORDERS 240105 0004.00 C DOW NOT %EOF() 240105 0005.00 C PNUM DSPLY 240105 0006.00 C READP ORDERS 240105 0007.00 C ENDDO 240105 0008.00 C SETON LR 240105
- READPE: This opcode is used to read an exact match of the key specified in the factor 1. If multiple records for an exact criterion are to be read, READPE can be used with SETXX opcodes with factor 1. Once a record is read it moves the pointer to next previous matching record for the key specified in factor 1.
- If the matching criteria is not found the EOF condition is reached.
- To handle exceptions, operation extender (e) can be used.
- READC: This opcode is used with subfiles, and it helps in identifying which subfile records have been modified. Exceptions can be handled by operation extender (e) and EOF indicator is set once the EOF condition is met. See below example where READC is being used to read changed record from subfile SFLORD.
0008.01 C READC SFLORD 0008.02 C DOW NOT %EOF 0008.03 C SELECT 0008.04 C ACTION WHENEQ '1' 0008.05 C EXSR HEADER 0008.06 C ACTION WHENEQ '2' 0008.07 C EXSR DETAIL 0008.08 C ACTION WHENEQ '4' 0008.09 C EXSR FOOTER 0008.10 C ACTION WHENEQ '5' 0008.11 C EXSR SUM 0008.12 C OTHER 0008.13 C EXSR VALIDATE 0008.14 C ENDSL 0008.15 C READC SFLORD 0008.16 C ENDDO
- CHAIN: This opcode is used to find an exact match for the value specified in factor 1. Under the covers, it is similar to SETLL and READE. The only difference is CHAIN cannot fetch the second exact match if used in a do-while loop. You can also use RRN number as factor 1 for sequential read if the file does not have any key defined.Operation extenders (n) and (e) can be used to for reading the record with no lock and error handling respectively.
0172.00 C EVAL KEYV = S_PNUM 0173.00 C KEYV CHAIN(E) HDRREC 0174.00 C IF %FOUND() 0175.00 C EVAL ORDBADD = S_ADDR 0176.00 C UPDATE HDRREC 0177.00 C ENDIF
Write Op-Code:
This opcode creates a new record in a database file or can be used with display files to output data on the screen. The opcode supports data structures as well. Below is an example for file ORDER with record format ORDERA.
Without Data structure
WRITE ORDERA;
With Data structure
WRITE ORDERA record;
Update Op-Code:
This opcode updates an existing record in a database. There should be a read operation prior to the update opcode. The opcode supports data structures as well. Below is an example for file ORDER with record format ORDERA.
Without Data structure
Update ORDERA;
With Data structure
Update ORDERA record;
Specific field update
Update ORDERA %fields(fld1:fld2:...);
Subroutines
A subroutine is a self-contained section of code within an RPG program that performs a specific task or set of tasks.
Subroutines in RPG are used to promote code reusability, modularity, and maintainability by encapsulating a particular functionality or calculation into a separate and callable unit.
RPG subroutines are defined using the EXSR (Execute Subroutine) operation code.
Syntax for Fix Format:
Exsr: It is used to call and process a subroutine.
Factor 1 | Code | Factor 2 | Result | Resulting indicator |
Exsr | Subroutine name |
Begsr: The op-code represents beginning of a subroutine placed in factor-1.
Factor 1 | Code | Factor 2 | Result | Resulting indicator |
Subroutine name | Begsr |
Endsr: ENDSR must be the last statement in the subroutine.
Factor 1 | Code | Factor 2 | Result | Resulting indicator |
Subroutine name | Endsr |
Syntax for Free Format:
Exsr: It is used to call and process a subroutine.
EXSR subroutine-name;
Begsr: The opcode represents beginning of a subroutine.
BEGSR subroutine-name;
Endsr: ENDSR must be the last statement in the subroutine.
ENDSR;
Usage:
Subroutines in RPGLE are used to encapsulate a specific piece of functionality within a program. Here’s how subroutines are typically used in RPGLE:
- 1. Modularity: Subroutines allow us to divide our RPGLE program into smaller, manageable units of code. Each subroutine can be responsible for a specific task or operation.
- 2. Reusability: Once we define a subroutine, we can call it multiple times from within our program, providing code reusability. This reduces code duplication and ensures that changes to a particular functionality only need to be made in one place.
- 3. Readability: Subroutines make our RPGLE code more readable and understandable by breaking it into smaller, well-named, and well-documented units.
- 4. Encapsulation: Subroutines can encapsulate complex operations or algorithms, making the main program more focused on the overall flow and logic of the application.
Restriction:
Subroutines can be restricted or limited in various ways based on the programming context and the features of RPGLE itself.
Below are some common restrictions and limitations on subroutines in RPGLE:
- 1. No Nested Subroutines: RPGLE does not support nested subroutines. This means you cannot define a subroutine within another subroutine. Subroutines are standalone and independent.
- 2. No Recursion: RPGLE doesn’t directly support recursion within subroutines, which means a subroutine cannot call itself directly or indirectly. Recursive calls are not allowed, as RPGLE does not have the necessary stack management for recursion.
- 3. No Local Variables: RPGLE subroutines do not have local variables or local storage.
- 4. Compile-Time Binding: In RPGLE, subroutine calls are typically resolved at compile time rather than at runtime. This means that if you change a subroutine, you often need to recompile all programs that call it.
- 5. No Explicit Return Statements: RPGLE subroutines do not require explicit “return” statements like some other languages. Control returns automatically to the calling program or procedure at the end of the subroutine.
- 6. Shared Memory Space: All variables declared within a program, including subroutines, share the same memory space. This means no true local variables exist within subroutines.
- 7. Propagation of unhandled exceptions: Unhandled exceptions within subroutines propagate to the calling program or higher-level exception handlers.
Best Practices:
- 1. Design subroutines with clear error handling strategies.
- 2. Use return codes and indicators effectively for error signalling.
- 3. Consider external procedures or sub procedures for more structured exception handling.
Example in Fix format:
Here’s a breakdown of the example:
- a) In first three line declare the variables.
- b) On 7th line firstly Execute the subroutine with EXSR it is the operation code used to execute the subroutine and then in the factor2 have subroutine name.
- c) Additionally, we will define the subroutine elsewhere in our program.
- d) On 8th line start the subroutine process with BEGSR. This is the operation code that marks the beginning of the subroutine.
- e) From 9th line to 12th subroutine logic code.
- f) On 13 line is end of the subroutine with ENDSR. This operation code marks the end of the subroutine.
Free format example:
Here’s a breakdown of the example:
- a) In first three line declare the variable.
- b) On 6th line firstly Execute the subroutine with EXSR and subroutine name.
- c) Additionally, we will define the subroutine elsewhere in our program.
- d) On 8th line start the subroutine process with BEGSR. This is the operation code that marks the beginning of the subroutine.
- e) From 9th line to 12th subroutine logic code.
- f) On 13 line is end of the subroutine with ENDSR. This operation code marks the end of the subroutine.
Subroutines in RPG are a way to modularize your code and make it more organized and readable. You can call a subroutine multiple times from different parts of your program, and it allows you to encapsulate and reuse specific logic.
Error Handling
Introduction
Exception handling in the AS400 system involves the process of gracefully managing and recovering from errors, exceptions, or abnormal conditions that may arise during program execution or system operations. It plays a critical role in ensuring the reliability, robustness, and integrity of applications running on the AS400.
RPG Exception Handling
RPG classifies exceptions into two main categories:
- Program Exception: Some examples of program exceptions are division by zero, array index out-of-bounds, SQRT of a negative number, invalid date, time, or timestamp value.
- File Exception: Some examples of file exceptions are undefined record type or a device error, record lock, update operation attempted without a prior read.
Status code
%STATUS code is a built-in function used to retrieve the status code of the most recent operation performed by operation codes within the program. This status code serves as an indicator of the success or failure of the operation. Typically, a status code of 0 signifies that the operation was completed successfully, while non-zero values indicate various types of error or exceptional conditions encountered during the operation.
The error is identified by a five-digit status code provided by %STATUS. Program status codes go between 00100 and 00999, whereas file status codes fall between 01000 and 01999. When a status code falls between 00000 and 00050, it is regarded as normal; that is, it is not caused by an exception or error situation.
There are different ways to indicate that RPG should handle an exception.
- (a) Using error IndicatorIf the calculation specification has an error indicator for an operation and an exception is expected for that operation:
- The indicator is set on.
- The exception is handled.
- Control resumes with the next RPG operation.
Sample code:
FEMPMASTER UF A E DISK USROPN C 5 SETLL EMPR 33 C EXSR INDERRSR C EVAL EMPNAME = 'ALEXA' C UPDATE EMPR 33 C EXSR INDERRSR C SETON LR C INDERRSR BEGSR C IF *IN33 = *ON C IF %STATUS(EMPMASTER) = 1211 C OPEN EMPMASTER C ELSEIF %STATUS(EMPMASTER) = 1221 C READ(E) EMPMASTER C EVAL EMPNAME = 'ALEXA' C UPDATE(E) EMPR C ENDIF C ENDIF C ENDSR
(b) Using Operator Extender (E)
If an ‘E’ operation code extender is included in the calculation specification and no error indicator is present, the error will be managed by this operator extender.
%STATUS and %ERROR, two built-in functions, will be used to handle the error.
Sample Code:
Dcl-F EmpMaster Usage(*Input:*Update:*Output) UsrOpn; Setll(E) 5 EmpR; Exsr ErrSr; EmpName = 'ABC'; Update(E) EmpR; Exsr ErrSr; *Inlr = *On; Begsr ErrSr; If %Error(); If %Status(EmpMaster) = 1211; Open EmpMaster; Elseif %Status(EmpMaster) = 1221; Read(E) EmpMaster; EmpName = 'ABC'; Update(E) EmpR; Endif; Endif; Endsr;
- Using Monitor BlockA MONITOR group performs conditional error handling based on the status code. It consists of:
- A Monitor Block
- Zero or more ON-ERROR blocks
- An ENDMON statement
Control moves on to the following statement after the MONITOR statement. The statements from the MONITOR statement to the first ON-ERROR statement make up the monitor block. Control is transferred to the relevant ON-ERROR block if an error arises during the processing of the monitor block.
If all the statements in the MONITOR block execute successfully without errors, control proceeds to the statement following the ENDMON.
Anywhere in the calculations, the monitor group can be provided. Within IF, DO, SELECT, or other monitor groups, it can be nested. Within monitor groups, the IF, DO, and SELECT groups can be nested.
Level indicators can be used on the MONITOR operation, to indicate that the MONITOR group is part of total calculations.
On the MONITOR statement, conditioning indicators are applicable. If they are not satisfied, control passes immediately to the statement following the ENDMON statement of the monitor group. Conditioning indicators cannot be used on ON-ERROR operations individually.
When a subprocedure called from a MONITOR block encounters an error, the subprocedure ‘s error handling will take precedence. For instance, the *PSSR subroutine within the sub procedure will be called. Only if the sub procedure is unable to handle the error and the call fails with the error-in-call status of 00202 will the MONITOR group containing the call be taken into consideration.
Errors that arise in a subroutine that is called from an EXSR statement within the monitor group are handled by the monitor group. The subroutine’s monitor groups take precedence if it has any.
Branching operations are not allowed within a MONITOR block but are allowed within an ON-ERROR block.
A monitor block’s LEAVE or ITER operations are applicable to all active DO groups that include the monitor block. For every subroutine, sub procedure, or procedure that contains a monitor block, the LEAVESR or RETURN operation is applicable.
A few examples are given below. The first involves figuring out how to capture a “divide by zero” error with the program status code 00102:
Sample Code:
Dcl-S Num1 Zoned(2:0); Dcl-S Num2 Zoned(2:0); Dcl-S Result Zoned(5:0); Dcl-S Error Char(50); Num1 = 10; Monitor; Result = Num1/Num2; On-Error 102; Result = 0; Error = 'Divide by 0'; EndMon; *Inlr = *On;
Example2:
Sample Code:
Dcl-F EmpMaster Usage(*Input); Dcl-S Error Char(20); Monitor; Open EmpMaster; On-Error *File; Error = 'File Not Opened'; EndMon; *Inlr = *On;
- Using an Error Subroutine(a) Using a File Error (INFSR) Subroutine.To handle a file error or exception, you can write a file error (INFSR) subroutine. When a file exception occurs:
- The INFDS is updated.
- A file error subroutine (INFSR) receives control if the exception occurs:
A file error subroutine can handle errors in more than one file.
The following restrictions apply:
- If an error occurs that is not related to the operation (for example, an array-index error on a CHAIN operation), then any INFSR error subroutine would be ignored. The error would be treated like any other program error.
- Control passes to the RPG default exception handler rather than the error subroutine handler if a file exception arises at the beginning or end of a program (for instance, on an implicit open at the beginning of the cycle). As such, there will be no processing of the file error subroutine.
- Errors in a global file used by a sub procedure cannot be handled by an INFSR.
Take the following actions to include a file error subroutine in your program:
- On a File Description specification, type the subroutine’s name after the keyword INFSR. The program error subroutine may be assigned control over the exception on this file if the subroutine name is *PSSR.
- You can use the keyword INFDS to optionally identify the file information data structure on a File Description specification.
- Enter a BEGSR operation in which the subroutine name specified for the keyword INFSR appears in the Factor 1 entry.
- Determine whether there is a return point and code it on the subroutine’s ENDSR operation.
- Code the rest of the file error subroutine. While any of the ILE RPG compiler operations can be used in the file error subroutine, it is not recommended that you use I/O operations to the same file that got the error. The ENDSR operation must be the last specification for the file error subroutine.
Sample Code:
Dcl-F EmpMaster Usage(*Input:*Update:*Output) INFDS(INFDS) Keyed INFSR(InfoSr) Usropn; Dcl-Ds InfDs; File_Status *Status; End-Ds; Dcl-S ReturnCd Char(6); Setll 00002 EmpR; EmpName = 'ABC'; Update EmpR; *Inlr = *On; Begsr InfoSr; If File_Status = 1211; Open EmpMaster; ReturnCd = '*GETIN'; Elseif File_Status = 1221; Read(E) EmpMaster; Update(E) EmpR; ReturnCd = '*CANCL'; Endif; Endsr ReturnCd;
(b) Using a Program Error Subroutine.
Program error subroutines (*PSSR) can be written to handle exceptions or program errors. When a program error occurs:
- The program status data structure is updated.
- If an indicator is not specified in positions 73 and 74 for the operation code, the error is handled, and control is transferred to the *PSSR.
After a file error, you can explicitly move control to a program error subroutine by adding *PSSR to the File Description specifications after the keyword INFSR.
For any procedure within the module, a *PSSR can be coded. Every *PSSR is specific to the coding procedure.
To add a *PSSR error subroutine to your program, you do the following steps:
- Optionally identify the program status data structure (PSDS) by specifying an S in position 23 of the definition specification.
- Enter a BEGSR operation with a Factor 1 entry of *PSSR.
- Identify a return point, if any, and code it on the ENDSR operation in the subroutine.
- Code the rest of the program error subroutine. Any of the ILE RPG compiler operations can be used in the program error subroutine. The ENDSR operation must be the last specification for the program error subroutine.
Sample Code:
Dcl-S Num1 Zoned(2:0); Dcl-s Num2 Zoned(2:0); Dcl-S Result Zoned(5:0); Dcl-S Error Char(20); Dcl-S ReturnCd Char(6); Dcl-Ds PSDS1 psds; Pgm_Status *Status; End-Ds; Num1 = 10; Result = Num1/Num2; *Inlr = *On; Begsr *Pssr; If Pgm_Status = 00102; Error = 'Divide by zero'; ReturnCd = ' '; Else; Error = 'Error with status code'; ReturnCd = '*CANCL'; Endif; Endsr ReturnCd;
- Default exception Handler.The RPG default error handler is called if there is no error indicator, ‘E’ extender, or error subroutine coded and no active MONITOR group could handle the exception.Sample Code:
Dcl-F EmpMaster Usage(*Input:*Update:*Output); Setll 5 EmpR; EmpName = 'ABC'; Update EmpR; *Inlr = *On;
CL Program Exception Handling
Monitor Message (MONMSG)
The monitor message (MONMSG) command enables us to take corrective action for escape, status, and notification messages that are present in a CL program at run time.
The messages are sent to the program message queue for the conditions specified in the command. If condition exists, the CL command specified on the MONMSG command runs.
It doesn’t handle diagnostic messages, but we can receive those messages from the message queue to get additional information related to the error.
Types of monitor message
- Escape MessageAn escape message alerts your program to an error that prompted the sender to terminate the program.
You can terminate your program or take corrective action by monitoring for escape messages. - Status or Notify MessageAn abnormal condition that is not severe enough for the sender to terminate is reported to your program via status and notification messages. By monitoring for status or notify message, your program can detect this condition and not allow the function to continue.Two levels of MONMSG command:
- Program levelIn the CL program, the MONMSG is defined right after the final declared command.
It will detect all error escape messages present in the program, regardless of whether there are any command level MONMSGs or not.Sample code:PGM DCLF FILE(EMPMASTER) OPNID(OPNID1) /* Program Level MONMSG */ MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR)) CHKOBJ OBJ(*LIBL/EMPMASTER) OBJTYPE(*FILE) MBR(*FIRST) ERROR: SNDPGMMSG MSG('Object not found in the *LIBL') ENDPGM
- command level.Here the MONMSG command immediately follows a CL command. If there is any error at a particular CL statement and it satisfies the condition specified in MONMSG, then the error is caught with this MONMSG.Sample Code:
PGM DCLF FILE(EMPMASTER) OPNID(OPNID1) /* Command Level MONMSG */ CHKOBJ OBJ(*LIBL/EMPMASTER) OBJTYPE(*FILE) MBR(*FIRST) MONMSG MSGID(CPF9801) EXEC(GOTO CMDLBL(ERROR)) READ: RCVF OPNID(OPNID1) MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(END)) GOTO READ ERROR: SNDPGMMSG MSG('Object not found in the *LIBL') END: ENDPGM
- Program levelIn the CL program, the MONMSG is defined right after the final declared command.
Load All Subfile
In this instance, the SFLSIZ indicates the number of total records can be loaded and SFLPAG indicates number of per page records in subfile.
The maximum value for SFLSIZ can be 9999.
In load all subfile, the system automatically handles PAGEUP and PAGEDOWN.
Usage:
Load all subfile program can be written in RPG, SQLRPG, RPGLE, SQLRPGLE.
We also need to create a display file (DSPF).
Restrictions and compatibility:
It can display maximum of 9999 records to the subfile, if more records need to be display then load all subfile is not compatible.
Code Example:
Physical file – EMPLOYEE
Column Names | Data Type | Length | Decimal | Description |
---|---|---|---|---|
EMPNO | Zoned Decimal | 10 | 0 | EMPLOYEE NUMBER |
EMPNAME | Character | 20 | EMPLOYEE NAME | |
EMPDEPT | Character | 10 | DEPARTMENT | |
EMPMOBNO | Zoned Decimal | 10 | 0 | MOBNO NO |
Display file – EMPLOYEED
In EMPSFL subfile record format, we defined the fields to be populated in the subfile.
In EMPCTL subfile control record format, we defined the required header information or header fields to be populated.
In EMPFTR record format, we defined footer information displayed below the subfile record format.
We used OVERLAY keyword in subfile control record format to overlay EMPFTR record format to the subfile.
In line 13.00, we defined SFLDSP keyword with indicator 51, this will be used in RPG program to display subfile record format.
In line 14.00, we defined SFLDSPCTL keyword with indicator 52, this will be used in RPG program to display subfile control record format.
In line 15.00, we defined SFLCLR keyword with indicator 53, this will be used in RPG program to clear the subfile before loading the subfile.
In line 16.00, we defined SFLEND keyword with indicator 54, this will be used in RPG program to display more if next page is there for the records and display bottom for the last page of subfile records.
RPGLE Program –EMPLOYEER (Free format)
Line 7.00 – decalaration of physical file EMPLOYEE
Line 8.00 – decalaration of display file with subfile record EMPSFL. We used keyword SFILE to reference subfile record relative number (RRN) for the subfile.
In this clearSubfile subroutine, we turned on SFLCLR indicator *IN53 to clear the subfile and writing subfile control record format.
In line 30.00, we initialize the record relative number (RRN) with 0
In this loadSubfile subroutine, we are reading the file EMPLOYEE from top to bottom and writing to subfile record format by increamenting subfile record relative number (RRN).
When SFLEND indicator *IN54 will be turned off, more will be shown at the bottom right of the subfile records.
When SFLEND indicator *IN54 will be turned on, bottom will be shown at the bottom right of the subfile records.
In displaySubfile subroutine, we are displaying the subfile by turning on SFLDSPCTL indicator *IN52.
SFLDSP indicator *IN51 will be turned on if records written to the subfile are greater than 1.
In line 67.00, we are writing the footer record format which will be overlayed to the subfile.
In line 68.00, we are displaying the subfile by using EXFMT keyword which is the combination of keywords WRITE and READ.
When F3 (*IN03) or F12 (*IN12) will be pressed, it will come out from the subfile.
RPGLE Program – EMPLOYEER (Fix format)
Calling program EMPLOYEER, displaying load all subfile with loaded data from physical file EMPLOYEE as shown below –
After pressing pagedown, shown below –
Expandable Subfile
Index
- Introduction
- Example
- Usage of Expanding Subfile
- Restrictions of Expanding Subfile
Introduction
Expandable Subfile is also referred to as an elastic or growing subfile because of its increasing nature. Unlike Load all subfiles where all 9999 records are loaded into the buffer in a single shot, the expandable subfiles load data into the buffer one page at a time.
Since data will be loaded into buffer only upon PAGEDOWN, this case needs to be handled. PAGEUP will be automatically handled by the system since data is already loaded into the buffer.
The basic ask for an Expandable Subfile while defining the DDS source is for the SFLSIZ to be at least one higher than the SFLPAG. The subfile buffer’s SFLSIZ is expanded to hold all records up to the buffer limit of 9999.
Example
Display File: CUSTDSPF
Main Program: CUSTMAIN
Output:
Uses of Expandable subfile
- When you want to show a lot of records but are unsure of the exact size ahead of time, expandable subfiles can be helpful.
- When showing client transactions, inventory goods, or staff data are among the situations where the quantity of records can differ greatly, they are frequently used.
- Always keep in mind that expandable subfiles are a useful tool for managing dynamic data in AS/400 programs because they offer flexibility and adaptability.
Restriction of Expandable Subfile
Performance: Due to the AS/400 system’s limited processing power and memory, expandable subfiles may experience performance problems with bigger datasets, even though they are effective for smaller datasets.
Single Page Subfile
Index
- Introduction
- Examples
- Usage of Single Page Subfile
- Restrictions of Single Page Subfile
Introduction
- In AS/400 programming, A single-page subfile shows all of the accessible data on a single screen/Page, in contrast to a typical subfile, which may span numerous pages and require paging controls to traverse through the data.
- The subfile page (SFLPAG) and subfile size (SFLSIZ) in this instance must match. This subfile is sometimes referred to as non-elastic, meaning that the buffer size will always be the same as the page size.
- The buffer is cleaned before writing each time a record is written there. Records the same as the size of SFLPAG are written after the subfile buffer has been cleared.
- PAGEUP and PAGEDOWN handling is necessary in this situation.
Example
Display File: DSPF
Main Program: CUSTMAIN
Output:
Usage of Single Page Subfile
In AS/400 programming, single page subfiles have significant benefits and are used in a variety of applications. The following are some typical applications for subfiles with one page:
- Data Inquiry Screens: When consumers need to access information fast without having to navigate through several pages, Single page subfiles are frequently employed. Customer information may be shown on a single page subfile, for instance, in a sales application’s customer search screen.
- Lookup Tables: These help show reference data or lookup tables that users need to see regularly. For easy access, a single page subfile can be used to display a product catalog in an inventory management system.
- Master Data Maintenance: Master data records, such as product or client information, may be displayed and edited using single page subfiles. Paging controls are not necessary because users may read and edit records on a single screen.
- Reporting: Single page subfiles can be used to present reports in scenarios when the dataset is small enough to fit on one screen. For ease of viewing, a daily sales report, for instance, may be presented as a Single page subfile.
- Dashboard Views: Dashboard views that give a summary of important metrics or performance indicators can be created using single page subfiles. All pertinent data is readily visible to users on a single screen.
- Workflow Management: Tasks or activities allocated to a user can be shown in single page subfiles inside workflow management apps. On a single screen, users may conveniently see and manage their responsibilities.
- Status Monitoring: They can be used to show information or provide real-time status updates. For simple monitoring, a monitoring program, for instance, can provide the current state of all system components on a single page subfile.
All things considered, single page subfiles in AS/400 programming provide a convenient means of presenting and interacting with data on a single screen, which makes them appropriate for a variety of uses in a variety of sectors.
Restrictions of Single Page Subfile
In AS/400 programming, single page subfiles provide several advantages, but there are also some constraints and limits to take into account.
- Limited Data Display: For showing comparatively modest datasets that easily fill one screen, single page subfiles are appropriate. It might not be feasible to use a single page subfile if the dataset is too big to fit on a single screen; instead, you might need to think about different pagination methods.
- Effect on Performance: When loading all of the data onto one screen, performance may suffer, particularly if there are complicated calculations or processing required, or if the dataset is big. Large dataset retrieval and formatting might tax system resources and degrade system performance.
- User Interface Clutter: When too much information is presented on one screen, the user interface may become crowded, making it challenging for users to locate the information they want. To guarantee clarity and usefulness, the screen layout must be properly designed.
- Limited Navigation: scrolling features for scrolling over several pages of data are not supported by single page subfiles. Users might not be able to see all of the data or move through it effectively if the dataset is larger than what fits on a single screen.
- Data Integrity: Data integrity may be compromised if entries are edited or updated directly on a single page subfile without first undergoing appropriate validation and error handling. Strong validation procedures must be used to guarantee the consistency and correctness of the data.
- Scalability: Single page subfiles become less effective as the dataset gets larger. If an application needs to handle progressively larger datasets over time, scalability could become a problem.
- Restricted ability: Depending on user settings or system circumstances, single page subfiles could not have the ability to dynamically alter the display or arrangement of data. Programming code modifications could be necessary to add or remove fields from the display.
Single page subfiles can nevertheless be a useful tool for presenting and engaging with tiny datasets in some applications, despite these limitations. However, while choosing whether to use single page subfiles in AS/400 programming, it’s crucial to carefully analyze the trade-offs in design and related constraints.
Printer Files
There are two different types of printer files:
- Program defined printer file
- Externally described printer file
1. Program defined printer file
A program described printer file is a printer file that is defined inside an application program. This indicates that the data division has internally defined descriptions for the file, record, and field. This approach involves hard-coding report specifications into the program, which are then included in the compiled object of the program.
Program:
Sample Code:
/Free Dcl-F SalAcc Usage(*input:*output) keyed; Dcl-F QPrint Printer(132) Usage(*output) Oflind(*In90); Except Header; Setll *Loval SalAcc; Read(n) SalAcc; Dow Not %Eof(SalAcc); If *In90 = *On; Except Header; Endif; Except Detail; Read(n) SalAcc; Enddo; Except Footer; *Inlr = *On; /End-Free OQPRINT E HEADER O 6 'PAGE' O Page 10 O 47 'SALARY ACCOUNT REPORT' O 65 'DATE' O Udate Y 75 O E HEADER 1 O 08 'EMPID' O 25 'DEPTCODE' O 40 'ACCOUNT NO' O 65 'SALARY STATUS' O E DETAIL 1 O EMPID 10 O DEPTCODE 22 O ACCOUNT_NO42 O STATUS 62 O E FOOTER 1 O 42 '******END OF REPORT******'
The program described printer file layout in O-SPECS shows how the records and their fields are supposed to print in the printer file.
In O-specs Press F4 define the QPRINT as an internal printer file and define a number of record formats. Defined Type E, by using the EXCEPT opcode as E(Exception) in O-specs, all record formats would be printed. First, we used the HEADER record format as EXCEPTNAME.
In O-specs assign the text “Page”, “SALARY ACCOUNT REPORT”, and “DATE” which will end at position 6, 47, and 65 respectively.
Defined the PAGE as field name at end position 10. Used PAGE system value to automatically set the page number for the printer file
we used the UDATE to get the six-digit date (mmddyy) and the edit code Y to format it using MM/DD/YY. Which will end at position 75.
The second record format is HEADER again, and it will only print the columns that contain “EMPID,” “DEPTCODE,” “ACCOUNT NO,” and “SALARY STATUS” at the end position that is specified. 1 is defined with HEADER to add one space before printing the second header record format.
We directly referred to the physical file fields EMPID, DEPTCODE, ACCOUNT_NO, and STATUS to be printed in the third record format, DETAIL, also 1 is defined with DETAIL which allows for one space before printing.
After printing all the details, we print the end of the report using the fourth record format, called FOOTER. 1 is defined with FOOTER to add one space before printing the second header record format.
Result
Advantages of Program-Defined Printer Files:
- The program is easy to maintain because the printer file specifications are directly embedded within it.
- During compilation, program and printer file changes are synchronized.
- There are no external dependencies because the printer file and the program are self-contained.
2. Externally described printer file
Any program that uses printer files that contain report specifications can define them externally. This indicates that a printer file’s report specifications are presented independently of any programs and combined into a printer file object.
Two ways to design an Externally described printer file:
- Design Externally described printer file using STRSEU.Create Source Member with type PRTF using STRSEU command.
This DDS entry’s designed screen is displayed below. Against this DDS source member, we choose option-19 in order to view the designed screen. - Design Externally described printer file using STRRLU:Step 1: Write STRRLU on the Command line then Press F4. Fill the Source Physical file, library, and source member name DEMOPRTF and press enter.Step 2: Insert line using then DR to define record format then VF to view field and press enter.
Step 3: On FLD1 write ‘SALARY ACCOUNT REPORT’ and press enter.
Step 4: Repeat step (2) to add more record format and field.
Step 5: Similarly, On FLD1 of RCD002 define the column as ‘EMPID’, ‘DEPTCODE’, ‘ACCOUNT NO’, and ‘SALARY STATUS’ and then press enter.
Step 6: On FLD1 Press F10 and give option 1 to add the fields from the database file SALACC and press enter. The selected field will show up at the bottom of the screen. Set the cursor at the FLD1 line where you want to add the field and Press Enter. The field definition will be placed there.
Step 7: Repeat step (2) and then Press F11 to define the field on FLD1 of RCD004 record format.
Step 8: Press SHIFT F6 + F10 to rename the record format. Rename RCD001 = HEADER, RCD002 = HEADER1, RCD003 = DETAIL, and RCD004 = FOOTER.
Example:
Program:
Sample Code:
Dcl-F SalAcc Usage(*input:*output) keyed; Dcl-F SalPrtf@ Printer Usage(*output) Oflind(*In90); Write Header1; Write Header2; Setll *Loval SalAcc; Read SalAcc; Dow Not %Eof(SalAcc); If *In90 = *On; Reset *IN90; Endif; Write Detail; Read SalAcc; Enddo; Write Footer; *Inlr = *On;
Result:
Advantages of Externally Described Printer Files:
- It’s not necessary to recompile the programs that use the printer file whenever changes are made. Such flexibility is very helpful when you need to change report layouts without having an impact on currently running programs.
- You can achieve better modularity and maintainability by separating report specifications from program logic.
- The same printer file can be shared by multiple programs, reducing redundancy and providing consistency.
- Data Description Specifications (DDS) for printer files with external descriptions can be created and reports can be generated using software tools.
Embedded SQL
Introduction
Embedded SQL programming in IBM i, empowers developers to seamlessly integrate SQL statements within RPG programs. This integration allows for efficient database interaction and manipulation tasks directly within the AS/400 environment.
Type of Embedded SQL
- Static SQL
- Static SQL involves SQL statements that are directly embedded within the source code of programs during compilation time.
- These statements cannot be changed or modified during runtime.
- Static SQL is suitable for scenarios where the SQL queries are known at compile time and do not need to be dynamically generated based on user input or other runtime conditions.
- Dynamic SQL
- Dynamic SQL allows for the generation and execution of SQL statements during runtime.
- Unlike static SQL, dynamic SQL statements can be constructed dynamically within the program based on runtime conditions, user input, or other variables.
- Dynamic SQL provides greater flexibility and versatility, as it enables programs to adapt to changing requirements or conditions at runtime.
Compilation command
CRTSQLRPG – To Create SQL RPG Program
CRTSQLRPGI – To Create SQL ILE RPG Object
Compilation Process
- Compared to a typical RPG application, embedded SQL requires a different compilation process.
- There are two sections to the compilation:
- SQL Pre-compilation: To verify the embedded SQL in the program and convert those into dynamic program calls. When a host variable, SQL statement selection field, or other SQL statement-related error is found, the compilation process ends, and a SQL pre-compilation report is produced.
- Main Program Compilation: Only the main program is built, and a successful compilation report is produced if there are no errors in the SQL pre-compilation.
Host Variable
The values that are retrieved by your program are put into data items such as Standalone variables/arrays/data structures/indicators that are defined by your program and that are indicated by a SELECT INTO or FETCH statement’s INTO clause. The data items are called host variables.
In SQL, a host variable refers to a field(Standalone variables/arrays/data structures/indicators) in your program that you specify within an SQL statement. Typically, it serves as the source or target for the value of a column. The host variable and the corresponding column must have compatible data types. However, it’s important to note that host variables cannot be used to identify SQL objects like tables or views, except in the context of the DESCRIBE TABLE statement
Note: When you utilize a host variable instead of a literal value in an SQL statement, you provide the application program with the flexibility to process various rows in a table or view.
- In a WHERE clause: Host variables allow you to define a value in the predicate of a search condition or to substitute a literal value within an expression. For example, in SQLRPGLE:
wkEmpID = ; exec sql Select empname into :wkEmpName from empMaster where empid = :wkEmpID;
- As a receiving area for column values (named in an INTO clause: When working with SQL, host variables allow you to define a program data area that will hold the column values of a retrieved row. The INTO clause specifies one or more host variables where you want to store the column values returned by the SQL query. This flexibility enables dynamic handling of data within your database operations. For example:
dcl-s wkEmpID char(6) inz; dcl-s wkEmpName char(50) inz; exec sql Select empid, empname into :wkEmpID, :wkEmpName from empMaster where empDept = ‘IT’ fetch first row only;
OR
dcl-ds empds dim(200) qualified; wkempID char(6) inz; wkempSal packed(11:2) inz; end-ds; exec sql Select empid, empSalary into :empDS from empMaster where empDept = ‘IT’ fetch first 200 rows only;
SQL Cursor
In IBM i, SQL cursors are essential constructs used to handle the result set returned by SQL queries within embedded SQL statements. A cursor allows programs to iterate over the rows of a result set sequentially, enabling row-level processing and manipulation of data retrieved from the database.
Creation Steps of Cursor:
- Prepare SQL statement (Optional)
dcl-ds empData extname(‘EMPMASTER’) qualified; end-ds; SQLstring = ‘Select * from empMaster where empid = ’ + wkEmpId; exec sql prepare SQLstmt from :SQLstring;
- Declare the Cursor
exec sql declare emp cursor for SQLstmt;
- Open the Cursor
exec sql open emp;
- Fetch from Cursor
exec sql fetch from emp into :empData; dow sqlcode =0; {logic block} exec sql fetch from emp into :empData; enddo;
- After all the records have been fetched, close the Cursor
exec sql close emp;
Type of SQL Cursor:
- Positioning based Cursor
Placing the cursor dynamically or sequentially at the resulting table rows divides the cursor into two types.- Serial/Sequential Cursor
- Scrollable Cursor
- Data-reflection-based CursorAfter opening the specific cursor, the modified data reflection into the cursor result table separates the cursor into two types.
- Sensitive Cursor
- Insensitive Cursor
Fetch for Rows:
To use the multiple-row FETCH statement with the host data structure array, the program must define a host data structure array that can be used by SQL.
- Number of Looping can be lowered down when you can fetch multiple rows at once.
- Declare your data structure with a dimension at the beginning.
- Declaring, opening, and closing the cursor is still necessary
- Fetch the number of rows equal to that data structure array size instead of a loop.
dcl-ds empData extname(‘EMPMASTER’) qualified dim(100); end-ds; dcl-s maxRows zoned(3) inz(100); exec sql declare getData cursor for select * from empMaster; exec sql open getData; exec sql fetch first from getData for :maxRows into :empData; rc = SQLER3; //SQLERR3 gives count of impacted rows from sql dow rc > 0; for i = 1 to rc; {logic block} endfor; exec sql fetch next from getData for :maxRows into :empData; rc = SQLER3; enddo;
Prepare SQL Statement
The PREPARE statement in the AS400 system is a powerful tool used by application programs to dynamically prepare SQL statements for execution.
- The PREPARE statement creates an executable SQL statement, known as a prepared statement, from a character string form of the statement called a statement string.
- It allows you to dynamically construct SQL statements at runtime, which is particularly useful when you need to parameterize your queries or execute dynamic SQL.
- Essentially, it prepares an SQL statement for later execution.
Execute Immediate SQL Statement
The EXECUTE IMMEDIATE statement offers a dynamic approach to executing SQL statements within a program. Unlike prepared SQL statements, which are pre-compiled and parameter-bound before execution, EXECUTE IMMEDIATE enables the execution of dynamically constructed SQL statements at runtime.
- The EXECUTE IMMEDIATE statement accepts a character string containing the SQL statement to be executed. This string can be dynamically constructed within the program.
- EXECUTE IMMEDIATE is particularly useful in scenarios where the structure or content of SQL statements cannot be determined statically at compile time.
Error Handling Indicator
SQLCODE:
- SQLCODE is a variable that stores the result code of the most recently executed SQL statement within an embedded SQL program.
- SQLCODE indicates the outcome of an SQL operation. Different values have different significance for execution of the statement. Most common values are 0 and 100 ( 0 indicates successful execution; 100 indicates end of records/no record impacted)and negative values indicate errors.
- After executing an SQL statement, check the value of SQLCODE to determine the outcome of the operation. Based on the result, appropriate actions can be taken.
SQLSTATE:
- SQLSTATE is a character variable that stores a five-character SQL state code representing the outcome of the most recent SQL operation.
- It offers additional details regarding the type of error or warning encountered during the execution of an SQL statement.
In IBM i embedded SQL programs, developers commonly utilize SQLCODE and SQLSTATE to identify and manage errors. This practice enables robust error handling and effective exception management within their applications.
Usage
- The dynamic usage of files within a program without needing F-specs.
- Data Retrieval and Manipulation
- Performance Optimization
- Data Integrity and Security
- Transaction Management
- Full SQL Capabilities
- Error Handling and Diagnostics
Tables and Arrays
ARRAY –
The array is a collection of elements having the same data type and length.
In RPG, we use ‘DIM’ keyword to define array.
There are 3 types of arrays in RPGLE –
- Run time array
- Compile time array
- Pre-runtime array
1. Run time array –
In Run time array, values will be filled to array during the run time only.
If any value is already assigned to array index, it can also be changed.
Fixed format example –
Line 1: Run time array name arr1 is defined with dimension 15 and length 10 having character data type for each element in array.
Line 2: A variable name index is defined with length (2,0) having zoned (numeric) data type.
Line 4: Assigning value to 1st index of array.
Line 5: Assigning value to 2nd index of array.
Line 6: Assigning index variable with value 3.
Line 7: Assigning value to 3rd index of array with the use of variable name index.
Free format example –
2. Compile time array –
In compile time array, values will be filled to array while compiling the program.
Values in compile time array cannot be changed during run time, values will be static in this.
Fix format example –
Line 1: Compile time array arr1 is defined with dimension 5 and length 20 having character data type.
The Keyword CTDATA is used to represent compile time array.
The keyword PERRCD is used to represent number of element values in each row.
Total number of elements (dim) = PERRCD elements * Number of rows.
Line 11: ‘**’ should be at position 1, after this we can give any readable name like (CTDATA arr1)
Line 12: Compile time array value for 1st index, as PERRCD is ‘1’ so this complete line will be assigned to 1st index.
Line 13: Compile time array value for 2nd index.
Line 14,15,16: Compile time array for 3rd, 4th, 5th index.
Once the program is compiled, all the values will be filled to array name arr1.
Line 5,6,7,8: Array values are used directly as array is filled while compile time.
Free format example:
3. Pre-runtime array –
The compile time array has some restrictions to change the values of array, if we want to change array value then we will need to make changes in program and recompile the program.
In pre-runtime array, we maintain the array elements in a separate file, if we want to change array element then we can change values in file, there is no need to recompile the program.
As array elements will be filled from the separate file so it will be filled while calling the program.
A flat file is a physical file that has a record length and no DDS (Data Description Specification).
Below is the command to create a flat file:
CRTPF FILE(YASHDEV/FLATF1) RCDLEN(20)
RCDLEN means, each record in file can be of length 20.
Below are the values added to the file for test data:
Fix format example:
Line 1: flat file FLATF1 is defined with file type as ‘I’ (input).
File Designation as ‘T’ to indicate an array or table file.
File Format as ‘F’ to indicate a program-described file.
Record Length as ’20’ to use length ’20’ for array element length.
Line 2: Pre-runtime array arr1 is defined with dimension 10 and length 20 having character data type.
Keyword FROMFILE is used to represent array to fill values from FLATF1 file.
Keyword PERRCD is used to represent the number of element values in each record of file.
While calling this program, it will fill the array from file FLATF1, and we can use the array directly.
Line 6,7,8,9: Array values are used directly without any array assignment.
arr(1) will be having value ‘Test value 1’ as per 1st record in file FLATF1 and PERRCD keyword with value ‘1’ for one element in one record.
Note: File Designation ‘T’ is not supported in fully free RPG format.
Tables –
In IBMi, tables are files which contain data in structural format.
There are 2 type of files –
- Physical files
- Logical files
1. Physical files –
Physical files include instructions on how to provide or receive data from a program in addition to the actual data that is kept on the system. They have one or more members and only one record format. Database files may contain externally or program-described records.
Physical files type is ‘*FILE’ and attribute is ‘PF’.
There can be multiple columns and keys in a physical file.
Creating a dds source of physical file: –
- We can create a physical file member dds by command ‘STRSEU’ and press F4 for prompt, below screen will be displayed to give details.
Source file – Source physical file name where we need to create a physical file.Library – Library name in which source file exists.
Source member – Physical file member name.
Source type – It should be ‘PF’ for physical file.Option – It can be blank for default. There are multiple option values –
2=Edit a member
5=Browse a member
6=Print MemberText description – It can be blank for default value. Also, we can give any text for our readability purposes.
Below is the dds source for an example physical file EMPPF-
Line 1: This is a file level keyword ‘UNIQUE’, which is to allow only unique records in this file as per defined key.
Keyword entries are optional in physical file, we can use as per our requirements.
There are 5 columns (EMPNO, EMPNAME, EMPGENDER, EMPEMAIL, EMPDEPT) defined in this physical file example.
There are ‘COLHDG’ keywords at field level, which is useful for readable name of columns.
There is a key EMPNO defined on line 8, which is useful to read the records from this physical file. We can give multiple keys in a physical file as per our requirements.
There are multiple levels for keyword entry –
- File level entries
- Record format level entries
- Field level entries
- Key field level entries
File level entries – file level entries work on entire file.
Below are the file level entries –
UNIQUE – It indicates that duplicate key values are not allowed
FIFO – It arranges duplicate key values in first-in, first-out order.
LIFO – It arranges duplicate key values in last-in, first-out order.
FCFO – It arranges duplicate key values in first-changed, first-out order
Record format level entries – It work for the defined record format.
Below are the record format level entries –
FORMAT – it shares field descriptions with an existing record format.
Below is the format of this keyword –
FORMAT(LIBNAME/FILENAME)
TEXT – It provides a description of the record or field.
Below is the format of this keyword –
TEXT(‘record format description’)
EDTCDE – It specifies an edit code (for reference function only).
EDTWRD – It provides an edit word (for reference function only).
REFFLD – It copies the field description from the referenced field.
REFSHIFT – It specifies a keyboard shift (for reference function only).
TEXT – It provides a description of the record or field.
TIMEFMT – It specifies the format of a TIME field.
TIMESEP – It specifies the separator used in the formatted TIME field.
VALUES – It provides a list of valid values (for reference function only).
VARLEN – It defines the field as a variable-length field.
Key field level entries – It work for the keys defined in physical file.
Below are the key field level entries –
DESCEND – It arranges records from the highest to the lowest key field value.
SIGNED – It arranges records using the sign portion of the key value.
ABSVAL – It arranges records using the absolute value of the key value.
UNSIGNED – It arranges records without using the sign portion of the key value.
ZONE – It arranges records using only the zone portion of the key value.
NOALTSEQ – It indicates to ignore any alternative collating sequence.
DIGIT – It arranges records using only the digit portion of the key value.
Below is the example (EMPPF1) of using REFFLD keyword –
Here, EMPNO field of EMPPF file is referenced to EMPNBR.
EMPNBR has the same data type and length as EMPNO field of EMPPF file.
We can ignore giving filename to define each field by using REF keyword at file level.
Below is the example of using REF keyword –
Creation of physical file object (Compile physical file)-
‘CRTPF’ is the command to compile physical file member. Type ‘CRTPF’ on command line and press F4 for prompt –
File – Object name for physical file.
Library – Object library in which physical file to be created.
Source file – Source file name in which physical file member is present.
Library – Library name in which source file is present.
Source member – Physical file member name.
Record length – It is used for flat file, it should be blank to compile physical file member.
Or we can use below command to create an object for physical file –
CRTPF FILE(&OBJLIB/&OBJNAME) SRCFILE(&SRCLIB/&SRCFILE) SRCMBR(&SRCMBR)
&OBJLIB – Object library in which physical file to be created.
&OBJNAME – Object name for physical file.
&SRCLIB – Library name in which source file is present.
&SRCFILE – Source file name in which physical file member is present.
&SRCMBR – Physical file member name.
CHGPF Command – The Change Physical File command changes the attributes of a physical file and all members of physical file. The changed attributes are used for all members subsequently added to the file unless other values are specified or default for the add operation.
Change Physical File Member (CHGPFM) command is used to change the attributes of a specific member.
Below is the CHGPF command –
CHGPF FILE(&OBJLIB/&OBJNAME) SRCFILE(&SRCLIB/&SRCFILE) SRCMBR(&SRCMBR)
&OBJLIB – Object library in which physical file to be created.
&OBJNAME – Object name for physical file.
&SRCLIB – Library name in which source file is present.
&SRCFILE – Source file name in which physical file member is present.
&SRCMBR – Physical file member name.
Other commands –
DSPFD – The Display File Description (DSPFD) command shows one or more types of information retrieved from the file descriptions of one or more database and/or device files.
Below is the DSPFD command to see all details of a physical file object –
DSPFD FILE(&FILELIB/&FILENAME)
&FILELIB – Physical file object library
&FILENAME – Physical file object name
DSPFFD – The Display File Field Description (DSPFFD) command shows, prints, or places in a database file field-level information for one or more files in a specific library or all the libraries to which the user has access.
Below is the DSPFFD command to see all details of a physical file fields –
DSPFFD FILE(&FILELIB/&FILENAME)
DSPDBR – The Display Database Relations (DSPDBR) command provides relational information about database files.
Below is the DSPFFD command to see all details of a physical file database relations –
DSPDBR FILE(&FILELIB/&FILENAME)
Logical files –
In AS/400, logical files are used to provide alternate views of physical files by specifying a different record sequence, selecting specific records, or reordering fields. Here’s a brief overview of the content for logical files:
Record Format Definitions:
Define the record format(s) that the logical file will use. These formats are typically based on the physical file’s record format but can include selected fields or reorganized data.
Key Field Definitions:
Specify key fields for the logical file. These fields determine the order of records in the logical file. The keys can include fields from one or more record formats.
File Type and Attributes:
Indicate the type of logical file (e.g., keyed or arrival sequence) and set attributes such as whether it’s updateable or read-only.
Select/OMIT Conditions:
Define conditions to selectively include or exclude records from the logical file based on specific criteria. This enhances data retrieval efficiency.
Join Logical Files:
If necessary, define join logical files that combine records from multiple physical files based on specified key relationships.
Access Paths:
Specify access paths for the logical file, which can include single-level or multi-level indexes. This helps optimize data retrieval operations.
Override Capabilities:
Utilize override capabilities to customize the behavior of the logical file, such as field renaming, data type conversion, or default values.
Example dds source for non-join logical file –
Line 1: we have used same record format name of physical file EMPPF.
PFILE is the keyword which indicates the logical file is based on EMPPF physical file.
Line 2,3: These are 2 fields which we select from physical file.
For no fields defined in logical file show all the fields.
Line 4: There is 1 key (EMPNO) defined for this logical file.
Line 5: This is definition of omit criteria, this logical file will omit the data in which EMPNO is greater than 30000.
Line 6: This is definition of select criteria, this logical file will select the data in which EMPNO is greater than 20000.
Join-Logical files –
In AS/400, join logical files are used to combine records from multiple physical files based on specified key relationships.
Here’s a basic overview of how you can create join logical files to join EMPPF and EMPPF3:
Below is the dds source for EMPPF physical file –
Below is the dds source for EMPPF3 physical file –
Below is the example dds source for EMPLF1 join logical file.
Line 1: There is a record format name defined EMPLFR and JFILE keyword is defined to join EMPPF and EMPPF3 physical files.
Line 2: There is a JOIN keyword which indicates the sequence of files.
Line 3: There is a JFLD keyword which indicates the fields of both files to join.
Line 4,5: There are EMPNO and EMPNAME fields are from EMPPF physical file.
Line 6,7: There are EMPADDR and EMPMOBNO fields are from EMPPF3 physical file.
Below is the command to compile logical file –
CRTLF FILE(&FILELIB/&FILENAME)
&FILELIB – Logical file object library
&FILENAME – Logical file object name
SQL Equivalent global temporary tables –
Global temporary tables are created in QTEMP library which is different for each session.
It will be used for current application process and cannot be shared with other application processes.
It can be used in SQLRPGLE program or executable interactively.
It can be used to eliminate the use of array or array ds in our application program by creating global temporary tables, writing data at run time and use as per program flow.
Below is the statement of global temporary table –
DECLARE GLOBAL TEMPORARY TABLE TEMP_EMP (EMPNBR CHAR(6) NOT NULL, EMPSAL DECIMAL(9, 2), EMPBONUS DECIMAL(9, 2), EMPDEPT CHAR(10)) ON COMMIT PRESERVE ROWS NOT LOGGED RCDFMT TEMP_EMPR;
In above SQL statement, a temporary table will be created in QTEMP library when declare global temporary table statement will be executed.
DECLARE GLOBAL TEMPORARY TABLE is the syntax to create TEMP_EMP table in QTEMP library.
There are 4 columns (EMPNBR, EMPSAL, EMPBONUS, EMPDEPT) defined.
ON COMMIT PRESERVE ROWS indicates that all rows of the table are preserved.
NOT LOGGED indicates that there will be no logs when changes are made to this table.
There is a record format TEMP_EMPR defined using RCDFMT.
We can declare a temporary table by using another table as below.
DECLARE GLOBAL TEMPORARY TABLE TEMP_EMP_1 LIKE LIBNAME/FILENAME ON COMMIT PRESERVE ROWS NOT LOGGED RCDFMT TEMP_EMPR1;
In above SQL statement, we have used LIKE keyword which indicates that this table has all the fields of FILENAME file which is present in LIBNAME library.
Below is the example of creating a global temporary table TEMP_EMP_2 having 3 columns (EMPNBR, EMPNAME, EMPSAL) from FILENAME file which is present in LIBNAME library and data for EMPNBR greater than 1000.
DECLARE GLOBAL TEMPORARY TABLE TEMP_EMP_2 AS (SELECT EMPNBR, EMPNAME, EMPSAL FROM LIBNAME/FILENAME WHERE EMPNBR > 1000) WITH DATA LIKE LIBNAME/FILENAME ON COMMIT PRESERVE ROWS NOT LOGGED RCDFMT TEMP_EMPR2;
Data Structure
Free Format
Fixed Format
Types of Data Structures in RPG
- Externally described Data Structures
- Multiple occurrence Data Structures
- Data area Data Structures
- Qualified Data Structures
- File information Data Structures
- Indicator Data Structures
- Program status Data Structures
- Externally described Data StructuresAn externally described data structure in RPG is a data structure whose definition is stored in an external file. This allows you to define the data structure once and then use it in multiple programs.
To define an externally described data structure, you can use the DCL-DS operation code and the EXT or EXTNAME keyword.
The EXT keyword specifies that the data structure definition is stored in an external file. The EXTNAME keyword specifies the name of the external file.
Here, we have used the externally described PF file (CUST).
Fixed format
Free format
- Multiple occurrence Data Structures A multiple occurrence data structure in RPG AS/400 is a data structure that can contain multiple occurrences of the same data. This can be useful for storing data that is repeated, such as a list of items in a purchase order or a table of data from a database.
To define a Multiple Occurrence data structure in RPG AS/400, you use the OCCURS keyword. The OCCURS keyword specifies the number of occurrences of the data structure that can exist.
Fixed format
Free format
Code example
- Data area Data Structures A data area data structure in RPG is a data structure that is defined in a program and is associated with a data area. Data area data structures are automatically read in and locked at program initialization time, and the contents of the data structure are written to the data area when the program ends with LR on.
Command to create a Data Area – CRTDTAARA
Command to display the Data Area – DSPDTAARA
Fixed format
Free Format
Code example
- Qualified Data StructuresThe qualified data structure is a data structure which allows us to define same fields into two or more data structures. A qualified data structure is used to group related data items together. Each data item within the qualified data structure has a qualified name, which includes the data structure name and the field name separated by a dot known as period.
Fixed format syntax
Free format syntax
Code example
- File information Data StructuresA file information data structure (INFDS) in RPG is a data structure that contains information about a file, such as the file status, file feedback, and input/output feedback. INFDS are used by RPG programs to handle file exceptions and errors.
Fixed format
Free format
Code example
- Indicator Data StructuresAn indicator data structure in RPG is a data structure that is used to store conditioning and response indicators for a workstation/display file (DSPF) and the printer file (PRTF). Indicator data structures are defined using the DCL-DS operation code and the INDDS keyword. The INDDS keyword specifies the name of the file that the indicator data structure is associated with.
INDARA keyword is declared in display file when we want to use an Indicator data structure.
Fixed format
Free format
- Program status Data StructuresA program status data structure (PSDS) in RPG is a data structure that contains information about the status of a program, including any errors that have occurred. The PSDS is defined in the main source section of the program and is accessible to all modules in the program. Only one PSDS is allowed per module.
Here, is the list of all the program status information.
Fixed format
Free format
Usage
- Group fields: Data structure can be used to group fields and can make a single string.
- Break fields into subfields: it can be used to break a string into several different fields.
Restrictions
- Fixed Format: RPG traditionally used fixed-format source code, which means that columns are predefined for specific purposes. This can limit the flexibility in defining data structures.
- Maximum Number of Elements: RPG has limits on the number of elements (fields) you can define in a data structure. The maximum number of elements varies depending on the RPG version and the specific compiler, but it’s typically around 99 elements.
- Field Names: Field names in RPG data structures must adhere to specific naming conventions. For example, they are limited to 10 characters in fixed-format RPG, and no limit in free-format RPG but the most preferred is 10 characters.
- No Dynamic Data Structures: RPG typically does not support dynamic data structures, such as linked lists or dynamically allocated arrays. Data structures are typically defined statically at compile time.
- Data Structure Alignment: RPG data structures may be subject to alignment requirements, which can affect the storage layout and padding of fields within a structure.