If you are an RPG programmer on the AS/400, you must know how to code subfiles. If subfiles are one technique you have been avoiding, this article may be just the ticket for you. We will cover the basics and definitions of coding subfiles in RPG.
Like many of the best features of the AS/400, the subfile originally appeared on the IBM S/38. The subfile was a method of storing data in memory to be presented on the screen in a columnar format much like a list. The program operator could page through the records or make a record selection for some type of further action. Since the migration to the AS/400, we have seen enhancements to the subfile with almost every new release of the OS/400 operating system.
Most of the complexity of subfiles is managed with special DDS keywords. A subfile is defined similarly to the way you define a database file. Subfile records can be read, chained to, written to, or updated much like a database file, but the data is stored temporarily in memory instead of permanently on disk.
Subfiles can help you present information clearly and concisely. Best of all, they're easy to set up and load on the AS/400, and they aren't a burden on your system resources if you know how to use them properly. The primary advantages of subfiles are performance, ease of coding and maintenance, and the ability to display and select multiple records with a single I/O operation to the workstation. This article will walk you through the basics of a simple customer inquiry subfile.
The two principle components of any subfile are the subfile record and the subfile control record. The subfile record is used to present a single element of information, much as a database record in the customer file contains information about one customer. In DDS, you define the format of the subfile record for a single element (e.g., each customer) and write multiple subfile records to display multiple records (e.g., a list of customers). The control record governs the behavior of the subfile; for example, the control record determines how many subfile records are displayed at a time. When coding DDS for a subfile, you must define the subfile record first and then the control record, although the control record typically appears at the top of the screen when you display a subfile.
1 shows sample output for our customer subfile example. The highlighted section of the display is defined in the subfile control record; the remainder of the display contains multiple subfile records.
Figure 1 shows sample output for our customer subfile example. The highlighted section of the display is defined in the subfile control record; the remainder of the display contains multiple subfile records.
2 contains the DDS for our subfile. The code for the subfile record format (SFLRCD) is similar to DDS for a database file. It contains two fields-SFNAME and SFACCT. When you define your subfile record format in DDS, you are actually creating the definition of a single record that will appear on your list. Values in the control record will determine how many records will be displayed at one time.
Figure 2 contains the DDS for our subfile. The code for the subfile record format (SFLRCD) is similar to DDS for a database file. It contains two fields-SFNAME and SFACCT. When you define your subfile record format in DDS, you are actually creating the definition of a single record that will appear on your list. Values in the control record will determine how many records will be displayed at one time.
A subfile record format must have at least one display field. The field locations in the DDS for the subfile record represent the line and the horizontal position of the fields as they will appear on the first subfile record displayed. The SFNAME and SFACCT fields in the example in 2 are displayed beginning on the seventh line in positions 2 and 36, respectively.
A subfile record format must have at least one display field. The field locations in the DDS for the subfile record represent the line and the horizontal position of the fields as they will appear on the first subfile record displayed. The SFNAME and SFACCT fields in the example in Figure 2 are displayed beginning on the seventh line in positions 2 and 36, respectively.
The subfile control record is used to control the presentation of the subfile through a series of keywords, which generally are managed with indicators. These keywords are used to specify how many records are in the subfile, which function keys are allowed, and how many records are displayed at one time. The control record can include input/output fields and is often used to display column headings for each field in the subfile. Understanding subfile control record coding is critical to understanding subfiles.
Four record-level keywords are mandatory for every subfile control record format: SFLCTL, SFLDSP, SFLPAG, and SFLSIZ.
o SFLCTL indicates that the record format will control a subfile. It must be coded directly after the subfile record format that it is to control. You must specify the name of the subfile record format as the parameter value for the SFLCTL keyword.
o SFLDSP indicates to the system that the subfile should be displayed when an output operation is performed on the subfile control record. An option indicator is usually coded with this keyword. If you perform an output operation to the subfile control record while this keyword is active and there are no subfile records to display, your program receives an error message. By indicating an option indicator on the SFLDSP keyword and turning it on only if there are subfile records to display, you avoid the error message.
o SFLPAG describes the size of the subfile page. Generally speaking, this keyword describes how many subfile records appear on the screen at one time. If each subfile record format takes up only one line of the screen (normally the case), this number matches the number of lines on the screen taken up by the subfile. On the other hand, if each subfile record format uses two lines, SFLPAG is half the number of lines required by the display file.
o SFLSIZ defines the number of records in the subfile. When considering how many records should be specified for SFLSIZ, you must consider the concept of the subfile as a temporary file stored in memory-not just the representation of the subfile on the screen. How this keyword affects the operation of the subfile depends upon whether or not SFLPAG and SFLSIZ are equal. We will discuss the possibilities in detail later in this article.
Other keywords that may be used on a subfile control record cover a wide variety of functions; in the interest of brevity, we will not cover all of them in this article.
To really understand the subfile DDS, we need to look at how it interacts with an RPG program. We have added the SFLDSPCTL, SFLCLR, SFLEND, and SFLRCDNBR keywords to our subfile control record; they will be discussed as we walk through the RPG code. The primary task of the RPG program is to load the subfile-fill it with specific data, some portion of which will be displayed on the screen under the control of the subfile control record.
Traditionally, three different methods are used to load subfiles: page-at-a-time, expanding, and load-all. You won't find these terms used in the IBM manuals, but they have become commonly known among programmers. With the page-at-a-time method, you write enough records to fill a single page of the subfile and then execute the subfile control format that will cause the subfile to be displayed. With the expanding subfile method, you write a specific number of records to the subfile (usually more than one page) and then display the subfile. If the user pages down beyond the end of the subfile, your program loads more subfile records, causing the subfile to expand. With the load-all method, you write all database records to the subfile before executing the control format.
The load-all subfile type should be used only when there is a small number of records that will ever be displayed. Because this is often difficult to predict, we recommend coding page-at-a-time or expanding subfiles.
Regardless of whether you are writing a page-at-a-time, an expanding, or a load-all subfile, the combination of the SFLSIZ and SFLPAG keywords determines how paging is handled for the subfile. When SFLSIZ and SFLPAG are the same, the maximum number of records allowed in the subfile can never exceed the number of records to be displayed on a single page. When an operator presses the Page Up or Page Down keys, control is always returned to the RPG program.
When the values specified for SFLSIZ and SFLPAG are not the same, the system processes the Page Up and Page Down keys without returning control to the RPG program, as long as there are records in the subfile to scroll through. When the beginning or end of the subfile is encountered within the scrolling process, control is returned to the RPG program, where the decision to write more records or perform some other function can be made. In our example in 2, SFLPAG and SFLSIZ have different values. SFLPAG has a value of 12 (meaning that up to 12 records appear on the screen at one time) and SFLSIZ is 24 records.
When the values specified for SFLSIZ and SFLPAG are not the same, the system processes the Page Up and Page Down keys without returning control to the RPG program, as long as there are records in the subfile to scroll through. When the beginning or end of the subfile is encountered within the scrolling process, control is returned to the RPG program, where the decision to write more records or perform some other function can be made. In our example in Figure 2, SFLPAG and SFLSIZ have different values. SFLPAG has a value of 12 (meaning that up to 12 records appear on the screen at one time) and SFLSIZ is 24 records.
When SFLSIZ and SFLPAG are not the same, the subfile automatically extends itself to contain additional records if you write a subfile record with a relative-record number (RRN) greater than the value specified in the SFLSIZ keyword. It continues to extend itself up to 9,999 records, which is the maximum that may be specified for a subfile. In this example, if more than 24 records are written to the subfile, the system automatically extends the size of the subfile. This example combines techniques of a page-at-a-time subfile and an expanding subfile.
Deciding the initial size of the subfile can be important. If SFLSIZ is too big, memory is wasted, which could hurt overall response time. If the SFLSIZ is too small, the system may be working overtime to extend the size of the subfile continuously. In general, we like to code the SFLSIZ as two or three times the SFLPAG. This is based on experience, which shows that an operator typically scrolls through no more than two or three pages of subfile data before ending the program or resetting the subfile (e.g., selecting a different partial customer name).
The RPG program in 3 is used to display our customer inquiry subfile example. The first steps performed in our example are to read the first database record and set the initial conditioning indicators for our subfile control record format. We set on indicator 22, which conditions the SFLDSPCTL keyword so the subfile control record format appears on our first output operation.
The RPG program in Figure 3 is used to display our customer inquiry subfile example. The first steps performed in our example are to read the first database record and set the initial conditioning indicators for our subfile control record format. We set on indicator 22, which conditions the SFLDSPCTL keyword so the subfile control record format appears on our first output operation.
We then enter a loop that reads enough database records to fill a page of the subfile (12 records in this example) and displays the subfile control record with an EXFMT so the operator can decide what the next course of action should be. The loop has been coded, so the subfile remains active as long as the page keys are pressed. When the Enter key is pressed, the program exits the loop and the program terminates (indicator LR is set on).
For each record added to the subfile, field RRN is incremented by 1. RRN is a hidden field on the subfile control record. Unlike database files, subfiles can store data in hidden fields-fields that will not be displayed but can be used when you process the file. RRN is linked to the subfile in the RPG program with a continuation F-spec. One of the functions of RRN is to control the SFLRCDNBR keyword. SFLRCDNBR controls which page of the subfile is displayed based on the value of its associated field (in this case, RRN). By setting RRN to any record in the current page, we ensure that the most recent page of the subfile is always displayed.
We also turn on indicator 21, which conditions the SFLDSP keyword (see 2) if at least one record is written to the subfile. If we fail to condition SFLDSP and an attempt is made to display subfile records when no records have been written to the subfile, the system responds with an error message.
We also turn on indicator 21, which conditions the SFLDSP keyword (see Figure 2) if at least one record is written to the subfile. If we fail to condition SFLDSP and an attempt is made to display subfile records when no records have been written to the subfile, the system responds with an error message.
If the operator presses Page Down, control is returned to the RPG program (there are no more records in the subfile to display), and the program writes an additional page of data to the subfile without clearing the original records.
Taking this approach ensures that we have done the minimal number of disk I/O operations on the database file and there is initially very little memory required to store our subfile. Because we cannot be certain how many records our customer database file may contain, this is the most logical method to use when designing this subfile. With this design, the subfile could potentially grow extremely large if the operator presses Page Down repeatedly.
New pages of the subfile continue to be added to the subfile every time the Page Down key is pressed, until the end of the customer database file is reached. At that point, the SFLEND indicator (24) is turned on, which causes the literal Bottom to be displayed.
If the operator presses Page Up (after pressing Page Down at least once), the paging is handled entirely by OS/400 without ever having to return control to the RPG program until the beginning of the subfile is encountered. If the Page Up key is pressed at the beginning of the subfile, control is returned to the RPG program.
In this example, the beginning of the subfile and the beginning of the database file always coincide because the user does not have the ability to position the subfile. Typically, the subfile control record would include a positioning field in which the user could key in a starting point for scrolling through the subfile. For a customer inquiry such as this example, the user would enter a name or partial name; the program would set lower limits and begin filling the subfile.
When the user scrolls back beyond the beginning of the subfile, control is returned to the RPG program when he presses Page Up. It's up to you to decide what you want to do in this case. For example, you could issue an error message or you could simply allow the user to continue to scroll backward until he reaches the beginning of the database file. If you want to allow a user to scroll beyond the beginning of the subfile, you'll need a routine like the one illustrated in 4 to create additional subfile pages while the user scrolls backward. If you wanted to add this code to 3, you would need to execute the RLBACK subroutine when indicator 27 is on. The RLBACK subroutine clears out the subfile and repositions the database file pointer.
When the user scrolls back beyond the beginning of the subfile, control is returned to the RPG program when he presses Page Up. It's up to you to decide what you want to do in this case. For example, you could issue an error message or you could simply allow the user to continue to scroll backward until he reaches the beginning of the database file. If you want to allow a user to scroll beyond the beginning of the subfile, you'll need a routine like the one illustrated in Figure 4 to create additional subfile pages while the user scrolls backward. If you wanted to add this code to Figure 3, you would need to execute the RLBACK subroutine when indicator 27 is on. The RLBACK subroutine clears out the subfile and repositions the database file pointer.
Because the program is rolling backward through the data, the subfile must be cleared before writing a new set of subfile records so pages won't get out of sequence. This is done by performing an output operation to the subfile control record with the indicator set so SFLCLR is active. For this example, SFLCLR is conditioned on indicator 23. In the RLBACK subroutine, indicator 23 is set on and indicator 22 is set off before the subfile control record is written. Indicator 23 activates SFLCLR to clear the subfile; setting off indicator 22 deactivates the SFLDSPCTL keyword. Except for the WRITE to clear the subfile, indicator 22 is always on. This allows you to write data and accept input for the subfile control record. You must remember to reset your indicators (as we have done in 4) after clearing the subfile or you will experience problems with subsequent output to the display file.
Because the program is rolling backward through the data, the subfile must be cleared before writing a new set of subfile records so pages won't get out of sequence. This is done by performing an output operation to the subfile control record with the indicator set so SFLCLR is active. For this example, SFLCLR is conditioned on indicator 23. In the RLBACK subroutine, indicator 23 is set on and indicator 22 is set off before the subfile control record is written. Indicator 23 activates SFLCLR to clear the subfile; setting off indicator 22 deactivates the SFLDSPCTL keyword. Except for the WRITE to clear the subfile, indicator 22 is always on. This allows you to write data and accept input for the subfile control record. You must remember to reset your indicators (as we have done in Figure 4) after clearing the subfile or you will experience problems with subsequent output to the display file.
Before the subfile can be refilled, the database file must first be repositioned so the database file pointer corresponds to the first record in the subfile (failure to do so would result in two pages of data needing to be read). To complete the setting of the database file pointer, the program must then read backward until it has read enough records to fill a subfile page.
To reposition the database file pointer, the RLBACK subroutine first chains to the very first record in the subfile to get the record key that will be used to reposition the file. This is more efficient than reading backward through either the database file or the subfile because we may have accumulated many pages of data in the subfile before rollback was ever pressed. After the database file pointer has been reset and the subfile has been cleared, we can loop back up as if the user had pressed the Page Down key.
Do not make working with subfiles more difficult than it needs to be. We covered just the basics in this article, but the rest of it should be easy. Once you feel comfortable working with subfiles, break out your DDS manual and review the other subfile keywords. You will find that working with subfiles is not all that difficult and is well worth the time.
Doug Pence is the founder and Ron Hawkins is the research and development manager of Computer Processing Unlimited, Inc. in San Diego, California.
Subfiles Made Simple
Figure 1: The Example Subfile Display Panel
Subfiles Made Simple
Figure 2: DDS for the Customer Subfile
*. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 A R SFLRCD SFL A SFNAME 30A O 7 2 A SFACCT 10A O 7 36 A R SFLCTL SFLCTL(SFLRCD) A SFLSIZ(0024) A SFLPAG(0012) A 21 SFLDSP A 22 SFLDSPCTL A 23 SFLCLR A 24 SFLEND(*MORE) A 29 ROLLDOWN(27) A 30 ROLLUP(28) A RRN 4 0H SFLRCDNBR A 1 29'Customer Subfile' A DSPATR(HI UL) A 4 5'Press PAGE keys, or Enter to- A Cancel' A 6 2' Customer Name - A Customer Number' A DSPATR(HI UL) *. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7
Subfiles Made Simple
Figure 3: RPG Program for the Customer Subfile
*. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 FSUBFILE CF E WORKSTN F RRN KSFILE SFLRCD FCUSTOMERIF E K DISK C READ CUSTOMER 24 READ 1ST RECORD C MOVE *OFF *IN21 SETUP SFL CTL C MOVE *ON *IN22 C MOVE *OFF *IN23 C MOVE *OFF *IN29 C Z-ADD1 X 30 * 27 = page up -- 28 = page down C *IN27 DOUEQ*OFF STAY IN LOOP C *IN28 ANDEQ*OFF AS LONG AS PAGE C X DOWLE12 KEYS USED C *IN24 ANDEQ*OFF C MOVELNAME SFNAME LOAD SUBFILE C MOVE CUST# SFACCT C ADD 1 RRN 21 ACTIVATE SFLDSP C WRITESFLRCD C *IN24 IFEQ *OFF C READ CUSTOMER 24 C ADD 1 X C ENDIF C ENDDO C X IFEQ 13 C *IN24 ANDEQ*OFF C MOVE *ON *IN30 C ENDIF C EXFMTSFLCTL DSP/READ SUBFILE C Z-ADD1 X C MOVE *OFF *IN30 C ENDDO * C MOVE *ON *INLR * *. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7
Subfiles Made Simple
Figure 4: Subfile Rollback Example
*. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 C RLBACK BEGSR C 1 CHAINSFLRCD 41 RESET DATABASE C SFACCT SETLLCUSTOMER POINTER C MOVE *OFF *IN21 C MOVE *OFF *IN22 C MOVE *ON *IN23 C WRITESFLCTL CLEAR SUBFILE C MOVE *OFF *IN21 C MOVE *ON *IN22 C MOVE *OFF *IN23 C MOVE *ZEROS RRN C DO 12 FILE ONE PAGE C READPCUSTOMER 41 C *IN41 IFEQ *ON C *LOVAL SETLLCUSTOMER BEGINNING OF C READ CUSTOMER 41 FILE REACHED, C MOVE *OFF *IN29 C LEAVE START OVER C ENDIF C ENDDO C ENDSR *. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7
LATEST COMMENTS
MC Press Online