Most input and output functions are the same in free-format RPG IV as in fixed format, except for the location of the code within the source line
By Jim Martin
Editor's Note: This article is excerpted from chapter 5 of Free-Format RPG IV: Third Edition, by Jim Martin.
Another difference is the use of alternatives for a key list used in database I/O for Chain, Set, and similar operations. The key list is replaced by an inline composite argument list or a key data structure and the %Kds built-in function on the I/O operation. Also, database update now features the %Fields built-in function option.
In this chapter, we look at the operations, options, and built-in functions now available for database I/O, as well as for workstation I/O and printer output. You will find that the free-format approach to input and output varies little from the extended Factor 2 calculation format.
Input from database files comes from various operations: Read (Read next), ReadE (Read next equal), ReadP (Read prior), ReadePE (Read prior equal), Chain (Chain), Setll (Set lower limit), and Setgt (Set greater than). The set file pointer operations Setll and Setgt don’t provide data from a record, but they can furnish information about a file’s key (found or equal) without accessing the record data. Of course, the two set operations also set the file pointer.
If successful, all the read operations and Chain provide data from an entire record. If unsuccessful, these operations set a condition: “end-of-file” for the read operations or “not found” for Chain. In most programs, we check these conditions to determine what to do next. If end-of-file or not found is determined, the record data remains unchanged from a prior successful operation. If no prior successful operation occurred, the fields of the record retain their initial values.
If you are already familiar with the database input operations from your experience with fixed-format RPG, you will have no problem adjusting to free format. The big difference is that we cannot call on resulting indicators in free format, so we must use built-in functions to determine the outcome of attempted input or output functions. The built-in functions—%Eof, %Equal, %Error, and %Found—have been available for extended Factor 2 calculations for several years.
The %Eof built-in function tests a specified file for end-of-file. If you specify no file, %Eof checks the last file read for end-of-file. The function returns a value of the indicator data type: either '1' to signify that the end-of-file condition was met or '0' otherwise.
You can use the %Eof built-in with all read operations. In the case of read prior operations, %Eof lets you test for beginning-of-file. Listing 5-1 shows examples of read operations used with the %Eof built-in function.
Listing 5-1: Read operations using the %Eof built-in function
Another built-in function used with database input is %Found. You employ this function after a Chain operation to determine whether the record access was successful. Like the %Eof built-in function, %Found returns a value of the indicator data type: value '1' for record found or '0' for no record found. You can optionally specify the name of the file you want to test with %Found. If you specify no file name, the operation checks the most recent operation that sets a %Found condition. In addition to Chain, the following operations can set %Found: Check, Checkr, Delete, Lookup, Scan, Setgt, and Setll.
In Chapter 4, we reviewed keyed access for Chain and Set operations. Two alternatives are now available that eliminate the need for the Klist (Define a composite key) and Kfld (Define parts of a key) operations.
In the first method, a named data structure defined in definition specifications uses the keyword LikeRec with a data-file record name as its first parameter and the value *Key as its second parameter. (You can also use the keyword ExtName with the data-file record name and *Key.) The record name you specify should match the record name of the file that will be used in the Chain or similar operation in the calculations. The data structure becomes a qualified data structure, with subfields referenced using the form recordname.fieldname. The subfields of this data structure that are related to the keys of the file will be used as the argument key fields. In the calculations, the %Kds built-in function is used on the Chain, Set, or similar operation. This function has two parameters: the named data structure mentioned above and an optional constant that specifies how many key fields to use from the data structure in the operation. If omitted, the second parameter defaults to all key fields.
The second method available is the inline composite argument list, provided on the calculation operation line. You specify fields in a parameter-style list, and, together, these fields comprise the lookup key argument.
When you use either of these methods, no fixed-format calculations (for Klist and Kfld) are necessary. Listing 5-2 shows sample Chain operations that use the %Found built-in function and the two key list alternatives.
You can also use the %Found built-in function after a Setll or Setgt operation. In this situation, %Found returns the value '1' if there is a key in the file whose value is equal to or greater than the key list argument (for Setll) or whose value is greater than the key list argument (for Setgt).
Listing 5-2: Chain operation alternatives with the %Found built-in function
Another built-in function available for Read and Chain database operations is the %Error built-in function. To enable this function, you must specify the operation extender (E) on the Read or Chain operation. The (E) extender tells the compiler that you want to handle file errors associated with the Read or Chain. Specifying the (E) disables the RPG default error handler for the operation. The %Error built-in function returns a value of data type indicator: '1' if an error occurred or '0' otherwise.
If you use the (E) extender, it is important to include some kind of error handling in your program. To do so, code an If %Error statement after the Read or Chain, followed by the desired error handling. The (E) operation extender
provides the same function as placing an indicator in the low position of resulting indicators in the original fixed-format version of Read and Chain. If you place the (E) extender on a Read or Chain operation but do not test %Error, you are permitting an error to occur without action being taken. It is difficult to predict the harm that this omission might cause.
Listing 5-3 shows an example that uses the %Error function.
Listing 5-3: Chain and Read operations with the %Error built-in function
You can use the %Equal built-in function after a Setll operation to determine whether a record whose key matches the key list argument exists in the file. You can use a partial key in the key argument list as well. This combination can provide a valuable utility if the file being accessed has a multiple-field key.
For example, say you have an “on-order” file with a two-part key: customer number and order number. To determine whether a certain customer has one or more data records in the file, you need only code a Setll to the file, using the customer number as the argument, and then check the status of %Equal after the Setll. If the function returns '1', data exists for the customer, and the file pointer is positioned at the first record. If %equal returns '0', no data records exist for the customer.
Listing 5-4 illustrates using Setll and Setgt with built-in function %Equal.
Listing 5-4: Using Setll and Setgt with the %Equal built-in function
Data Area Input
Data areas, especially data area objects, could reasonably be called part of the database. You use the same data structures (definition specifications) regardless of the format of the calculations. Input from a data area is accomplished automatically, via the In operation, or by both methods.
The following operations perform output to database files: Write (Add a new record), Update (Modify an existing record), Delete (Delete a record), and, if you’re using program-described files, Except (Exception output).
The Write operation adds a new record to a file. No prior read is necessary, but the file must be opened before you request the Write. An entire record is written with the Write, and you must take care to ensure that all fields are loaded properly before the Write. If new records are to be added to a file, the file must have either a file type of O or an A in position 20 to denote that you plan to add records to the file being read (file type I) or updated (file type U).
The Update operation works the same in free format as before. However, a new built-in function, %Fields, gives free-format programmers the option to update only specified fields instead of an entire record. You can do this in fixed format by using the Except operation and output specifications, but the %Fields function is not available to fixed-format users of Update. Without the %Fields option, the entire record is modified using the current values of the fields defined in the record.
For an update to succeed, you must specify U (for update) on the file declaration, and a successful Read (or Chain) of a record must occur. During the time between the successful Read (or Chain) and the Update operation, the record is locked. No other user can access the record for update until the update is performed, another record is read, or an Unlock operation is performed. Be aware that record locking provides a needed function to maintain data integrity, but unless you program carefully, it can create operational grief.
The Delete operation removes a record from a file. If you specify no search argument, the operation deletes the record that was most recently read by a Read or Chain operation. If you specify a search argument (a relative record number or key), the compiler uses the argument to locate the record to delete. For files using a key, free format lets you use the %Kds built-in function or an in-line composite list instead of the fixed-format Klist to specify the search key.
To verify that the Delete operation found and deleted the record, you should use the %Found built-in function after the Delete. Using the search argument, no prior read is needed. After a delete using a key argument, the file pointer is positioned to the next record after the deleted one.
The Except operation uses a label to specify which output in output specifications to perform. The output specifications have a matching label on Exception output records. The function of Except output is identical to that in fixed-format calculations.
Listing 5-5 shows some sample database output operations and their built-in functions.
Listing 5-5: Database output operations and built-in functions
More of Jim's Free-Format RPG IV is coming soon in an upcoming issue of MC RPG Developer. Can't wait? You can pick up Jim Martin's book, Free-Format RPG IV: Third Edition at the MC Press Bookstore Today!