So you thought subfiles were nothing but a neat inquiry trick? Read on!
by Jonathan Yergin
Picture this. It is time to update the text for the device descriptions (*DEVD) on the AS/400. After six months of new user additions, office group moves, and employee changes, the text descriptions are out-of-date. The text contains the name of the user for each workstation and the name of the department for each printer. In addition, the D.P. Manager has decided to put the serial number of each device in the last 20 positions of the text.
To begin this task, a listing of all devices is printed using the command DSPOBJD OBJ(*ALL/*ALL) OBJTYPE(*DEVD) OUTPUT(*PRINT). Changes and corrections are red-inked on the listing, and now it is time to make the changes. How should this be done? Should we use the CHGOBJD command for each object and print another listing to verify the changes?
The programs we have included with this article allow you to change the text for all of your device descriptions (or for any other object type, for that matter) at one time with immediate on-screen verification (see Figures 1 and 2). The point of including the program in this article is to demonstrate several important techniques of subfile programming.
Last month we covered the very basics of subfile programming. This month we will explore the more advanced techniques of subfile cursor positioning, subfile entry with error handling, and read-changed-records processing. Refer to the code for the sample programs and screen in Figures 3a-3c as you follow the technical narrative.
Subfile Cursor Positioning
When the subfile is defined in such a way that it can contain more records than one page can hold (that is, when SFLSIZ is greater than SFLPAG), the result is a multi-page subfile. When two or more pages of records are written to the subfile, the operating system automatically supports and responds to the roll keys by displaying either the next or previous page of records; you do not have to include any code to support roll keys in your program. The multi-page subfile in our sample program is loaded by the subroutine that builds screen 1, FM01BL. The pseudocode in 4 illustrates this process.
When the subfile is defined in such a way that it can contain more records than one page can hold (that is, when SFLSIZ is greater than SFLPAG), the result is a multi-page subfile. When two or more pages of records are written to the subfile, the operating system automatically supports and responds to the roll keys by displaying either the next or previous page of records; you do not have to include any code to support roll keys in your program. The multi-page subfile in our sample program is loaded by the subroutine that builds screen 1, FM01BL. The pseudocode in Figure 4 illustrates this process.
Building the screen is done by first clearing the subfile and then loading it. To clear the subfile we perform an output operation (WRITE) to the subfile control record in such a way that the indicator conditioning the SFLCLR (subfile clear) keyword is ON. To load the subfile, all we need to do is to read the database file, one record at a time, writing the data contained in it into the subfile record and incrementing by 1 the subfile record number. This process is repeated until we reach the end of the database file. Notice that while the database file contains the object text field (ODOBTX), we move it to the subfile's record SOBTX so we can change it, since this is the purpose of the program we're developing.
After loading the subfile and before we display it, we must ensure that field SRCD contains a valid number. This field illustrates the keyword SFLRCDNBR(CURSOR) in the DDS of the display file; it specifies that the system will move the display cursor to the subfile record whose number is placed in this field. So if you were to move a number five into field SRCD, the system would automatically fetch the subfile page that has record number five, and display it - with the cursor automatically positioned on that fifth record. We will accomplish this positioning by providing an input field, SRCD. As you will see, it is a useful method for locating a specific subfile record. For instance, we could easily locate the fiftieth device description (in a subfile containing 100 descriptions) by keying 50 in the SRCD input field and pressing Enter. Notice, too, that we also use the field in our sample program to position the cursor at the first changed record that has errors.
Subfile Entry with Error Handling
There are four basic types of subfiles, categorized by their usage and the type of fields in the subfile record:
1. Display subfiles are used to display a group of like records for inquiry purposes. All fields are output only.
2. Selection subfiles are used to display records with the added capability of allowing a record to be selected for further processing (e.g., to display additional information, or make changes). An input-capable field is included for this purpose. If you have used the WRKSPLF or WRKOUTQ commands, you'll recall having typed option numbers (such as 4=Delete) on specific items.
3. Entry subfiles are used to enter a group of new records, such as line items in a purchase order. The fields must be input-capable and may be specified for both input and output.
4. Display and update subfiles are used to display records and make changes if desired. A typical use would be to provide a review mode in an order entry application, or a text editor like SEU. At least one field is specified for both input and output.
Creating an entry or display/update subfile is easy; the difficulty lies in providing for error handling. Assume a multi-page subfile, used for display and update, which contains five pages of records. The first objective for editing the records in the subfile is to process only the records that were changed; the READC operation code gives us this capability in RPG. The second objective is to highlight the records with errors and to position the cursor at the first offending record, thereby allowing easy correction. The display file keyword DSPATR(RI) takes care of the highlighting, showing in reverse video all error records; SFLRCDNBR(CURSOR) provides the capability of positioning the cursor at the first record having errors. The third objective, to re-display any errors until they are corrected, requires use of the SFLNXTCHG keyword, which we will explain later. 5 illustrates the process of providing for error handling in pseudocode.
Creating an entry or display/update subfile is easy; the difficulty lies in providing for error handling. Assume a multi-page subfile, used for display and update, which contains five pages of records. The first objective for editing the records in the subfile is to process only the records that were changed; the READC operation code gives us this capability in RPG. The second objective is to highlight the records with errors and to position the cursor at the first offending record, thereby allowing easy correction. The display file keyword DSPATR(RI) takes care of the highlighting, showing in reverse video all error records; SFLRCDNBR(CURSOR) provides the capability of positioning the cursor at the first record having errors. The third objective, to re-display any errors until they are corrected, requires use of the SFLNXTCHG keyword, which we will explain later. Figure 5 illustrates the process of providing for error handling in pseudocode.
RPG Operations for Subfile Records
The RPG operation which is the focus of our attention, READC, can be best understood in the context of all subfile operation codes. A request for input or output to a subfile record format either writes a record to a subfile or reads a record from a subfile, but does not cause actual I/O to the display. To write records to the display, the program must issue a request to the subfile control record. The valid requests for a subfile record are WRITE (with RRN specified), CHAIN (by RRN), UPDAT, and READC.
The WRITE or Put Relative operation adds a record to a subfile by relative record number (RRN). The lowest valid RRN is always 1. If the subfile size and page values are equal, the highest valid RRN is the subfile size value; otherwise, the highest valid RRN is 9999 since the operating system automatically extends the subfile as required. We use the WRITE operation code in the subroutine to build screen 1, FM01BL.
The CHAIN or Get Relative operation retrieves an active record from a subfile by relative record number. The record is passed to the program, the RRN is placed in the I/O feedback area (positions 376-377 of the WORKSTN file INFDS), and the record is reset as an active (not changed) record. If the record specified is not active, the indicator in positions 54 and 55 is set on. We do not use the CHAIN operation in our sample program, but have provided an example of its use in 6. The records in a single page subfile are processed in a DO loop which increments the subfile relative record number (SFLRN1) from 1 to 15. If the subfile record is active, the screen fields are moved to the file fields and a record is written to a transaction file.
The CHAIN or Get Relative operation retrieves an active record from a subfile by relative record number. The record is passed to the program, the RRN is placed in the I/O feedback area (positions 376-377 of the WORKSTN file INFDS), and the record is reset as an active (not changed) record. If the record specified is not active, the indicator in positions 54 and 55 is set on. We do not use the CHAIN operation in our sample program, but have provided an example of its use in Figure 6. The records in a single page subfile are processed in a DO loop which increments the subfile relative record number (SFLRN1) from 1 to 15. If the subfile record is active, the screen fields are moved to the file fields and a record is written to a transaction file.
The UPDAT operation updates an active record which was retrieved using CHAIN or READC. No other operations may be performed on the subfile to be updated between the read and the update, including subfile roll or SFLDROP processing. We use the UPDAT operation in the FM01ED subroutine to update each record that was read. If an error is found, indicator 14 is set on to enable the reverse-image attribute for the text field. The UPDAT operation actually applies this attribute to the subfile record.
Read-Changed-Records Processing
The READC or Get Next Changed operation reads the next changed record in the subfile. The first READC operation reads the first changed record. The record is passed to the program, the RRN is placed in the I/O feedback area, and the record is no longer identified as a changed record. Subsequent READC operations return the next changed record whose RRN is greater than the RRN in the feedback area. When no more changed records with a higher RRN exist, the indicator in positions 58 and 59 is set on.
The SFLNXTCHG keyword can be used to force the data entry operator to correct keying errors detected by the program. If a record retrieved by the READC operation is updated (UPDAT) with the SFLNXTCHG keyword in effect, the updated record is set again as a changed record. The next READC operation does not read this record because the changed records are accessed sequentially using the RRN in the feedback area as described before.
After all changed records are processed, the screen will be displayed again with any errors highlighted. If the operator presses Enter without making any corrections, the records with errors will again be returned by the READC operation. In this way our program will keep on rejecting the errors until they are corrected. We use this technique in our sample program. In the following discussion we "walk through" what happens when the Enter key is pressed.
As the first operation in the Enter key processing subroutine (FM0100), we execute the edit subroutine. In the FM01ED subroutine we set *IN91 on just before starting the read-changed loop. Indicator 91 is used to condition the SFLNXTCHG keyword. The first time through the loop we read the records that were actually changed on the screen. We update each record, and since SFLNXTCHG is in effect, each one is set again as a changed record. If errors are found, the screen will be displayed again until they are corrected. If no errors are found we execute the CHGTXT subroutine, which also uses a read-changed loop to process the subfile records. However, since this time the records are not updated with SFLNXTCHG in effect, they will no longer be identified as changed records.
Setting Up the Sample Program
Key and compile the CL program (SFL002CL), the RPG program (SFL002RG), and the display file (SFL002DF), then run the CL program. This program uses selective prompting to let you change the DSPOBJD command; simply specify *DEVD (device descriptions) for the object type. The results are placed in the output file and displayed for review and modification. An error results when the text field is blanked out in a changed record. If no errors are found, program QCMDEXC (QCAEXEC on the S/38) is called to execute the CHGOBJD command from within the RPG program. As a final note, please vary off the devices whose descriptions you are going to change. This function could be performed automatically by calling a CL program from the RPG program (instead of QCMDEXC) which would vary off the device, change its description, and vary it back on.
Summary and Challenge
This month we have examined subfile cursor positioning, subfile entry with error handling, and read-changed-records processing. We have discussed the RPG operations for subfile records with coding examples. The sample program demonstrates many of these techniques and provides a useful tool for maintaining the text descriptions for all objects on the system.
Programmers looking for a challenge are encouraged to explore further the message handling technique presented, and to develop additional edits. An additional edit for the subfile record would be to check for a serial number in the last 20 positions of the text. This error would be conditioned by indicator 15. An edit of the SRCD field could be used in place of the RANGE keyword. Indicator 11 could be used to condition an ERRMSG keyword for the field.
Roll on.
------------------------------------------------------------------------------- Sidebar: Subfile DDS Keywords -------------------------------------------------------------------------------
The following DDS keywords are required for a subfile:
SFL identifies the subfile record format. SFLCTL identifies the subfile control record format for the subfile record format which immediately precedes it. SFLSIZ specifies the size of the subfile. SFLPAG specifies the size of a subfile page. SFLDSP specifies that the subfile records are to be displayed.
The following optional DDS keywords may be used:
SFLCLR to clear all subfile records before writing new records. SFLDLT to delete a subfile if the maximum number of subfiles are in use and another is needed. This keyword is seldom needed. SFLDROP to specify a function key to be used to alternate between a folded or truncated display. SFLDSPCTL to display the subfile control record. This keyword must be in effect before any inpu t operation. SFLEND to specify that a plus sign (+) be displayed in the lower right corner of the subfile are a when more records exist. It will be replaced by a blank when the last record is displayed. SFLENTER to use the Enter key as the Roll Up key, and to define a function key as the Enter key. SFLINZ to cause input-capable fields for all subfile records to be initialized to their default values. SFLRNA to initialize the subfile with no active records. SFLLIN to specify the number of spaces between each record when more than one is displayed on a line. SFLMSG and SFLMSGID to display a message when the subfile control record is displayed. The cursor blinks and the keyboard is locked. The error is cleared by pressing the Reset key. SFLNXTCHG to cause a subfile record to be considered changed so that it will be returned by READC. SFLRCDNBR(CURSOR) to specify the page of a subfile to be displayed. The optional CURSOR param eter causes the cursor to be positioned in the record specified. SFLROLVAL to roll by a specified number of records instead of by a page. SFLMSGKEY, SFLMSGRCD, and SFLPGMQ to define a subfile to contain messages from a program message queue.
Subfile Fundamentals
Figure 1 Prompt for Display Object Description cmd
------------------------------------------------------------------------------- Figure 1: Prompt for Display Object Description Command ------------------------------------------------------------------------------- Display Object Description (DSPOBJD) Type choices, press Enter. Object . . . . . . . . . . . > *ALL______ Name, generic*, *ALL Library . . . . . . . . . > *LIBL Name, *LIBL, *USRLIBL... Object type . . . . . . . . > *devd_____ *ALL, *ALRTBL, *AUTL... + for more values __________ Detail . . . . . . . . . . . *BASIC *BASIC, *FULL, *SERVICE Output . . . . . . . . . . . > *OUTFILE *, *PRINT, *OUTFILE File to receive output . . . > QADSPOBJ Name Library . . . . . . . . . > QTEMP Name, *LIBL, *CURLIB Output member options: Member to receive output . *FIRST Name, *FIRST Replace or add records . . *REPLACE *REPLACE, *ADD Bottom F3=Exit F4=Prompt F5=Refresh F12=Cancel F13=How to use this display F24=More keys
Subfile Fundamentals
Figure 2 Subfile display of device descriptions
------------------------------------------------------------------------------- Figure 2: Subfile Display of Device Descriptions ------------------------------------------------------------------------------- mm/dd/yy hh:mm:ss OBJECT DESCRIPTION - *BASIC Position cursor at sequence: ___1 OBJECT TYPE TEXT DSP01 *DEVD System Console___________________________________ DSP02 *DEVD Clark Gable______________________________________ DSP03 *DEVD Douglas Fairbanks________________________________ DSP04 *DEVD Bette Davis______________________________________ DSP05 *DEVD Jane Wyman_______________________________________ DSP06 *DEVD Rodolfo Valentino________________________________ DSP07 *DEVD Judy Garland_____________________________________ DSP08 *DEVD Basil Rathbone___________________________________ DSP09 *DEVD Bela Lugosi______________________________________ DSP10 *DEVD Sammy Davis, Jr._________________________________ DSP11 *DEVD Mae West_________________________________________ DSP12 *DEVD Alfred Hitchcock_________________________________ DSP13 *DEVD Cecil B. DeMille_________________________________ F3=Exit -----------------------------------------------------------------------
Subfile Fundamentals
Figure 3A CL program SFL002CL
SFL002CL: + PGM DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(100) MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR)) ? DSPOBJD ??OBJ(*LIBL/*ALL) ??OBJTYPE(*ALL) ?*DETAIL(*N) + ?*OUTPUT(*OUTFILE) ?*OUTFILE(QTEMP/QADSPOBJ) ?*OUTMBR(*N) OVRDBF FILE(QADSPOBJ) TOFILE(QTEMP/QADSPOBJ) CALL PGM(SFL002RG) GOTO CMDLBL(ENDPGM) ERROR: + RCVMSG MSGDTA(&MSGDTA) MSGID(&MSGID) IF COND(&MSGID *NE ' ') THEN(DO) SNDPGMMSG MSGID(&MSGID) MSGF(QCPFMSG) MSGDTA(&MSGDTA) ENDDO ENDPGM: + ENDPGM
Subfile Fundamentals
Figure 3B RPG program SFL002RG
H F* F* SFL002RG - CHANGE OBJECT DESCRIPTIONS F* F* JEY 09/07/90 Original version. F* F* FILES USED F* NAME DESCRIPTION F* QADSPOBJ Outfile for DSPOBJD F* F* INDICATOR REFERENCE F* 01 Redisplay indicator F* 91 Record not found; loop control; SFLNXTCHG F* 92 Record not found; loop control F* 93 First changed record with error F* 98 Clear subfile F* N98 Display subfile F* FSFL002DFCF E WORKSTN F SFLRN1KSFILE FM01SFL FQADSPOBJUF E DISK E SFLM 2 1 Save SFLMSG *IN's E CMD 1 1 80 QCAEXEC command IDSCMD DS 80 I 9 18 DSOBNM I 20 27 DSOBTP I 30 79 DSOBTX C *LIKE DEFN SRCD SFLRN1 Define fields C*-- Main processing. ------------------------------* C EXSR ZFIRST Initialization C NXTSCN DOUEQ*BLANKS -1- Screen loop C NXTSCN CASEQ'FM01' FM01 -2- Screen CASE C CAS ZEXIT C END -2- C END -1- C MOVE '1' *INLR C RETRN Return C*-- Display and process screen FM01. --------------* C FM01 BEGSR C EXSR FM01BL Build screen C WRITEFM01HDR Write header & C WRITEFM01CK command keys C MOVE '1' *IN01 Screen display C *IN01 DOWEQ'1' -1- loop C MOVE '0' *IN01 C EXFMTFM01CTL C *INKC CASEQ'1' FM0103 -2- F3=Exit C CAS FM0100 Enter key C END -2- C END -1- C ENDSR C*-- Build screen FM01. ----------------------------* C FM01BL BEGSR C MOVEA'00000' *IN,11 Reset errors C MOVE '1' *IN98 Clear subfile C WRITEFM01CTL C MOVE '0' *IN98 C MOVE *ZEROS SFLRN1 *------------ C 1 SETLLQLIDOBJD 91 Load subfile C *IN91 DOWEQ'0' -1- C READ QLIDOBJD 91 C *IN91 IFEQ '0' -2- C MOVE ODOBTX SOBTX C ADD 1 SFLRN1 Write subfile C WRITEFM01SFL record C END -2- C END -1- *---------/ C SRCD IFEQ *ZEROS -9- Subfile C Z-ADD1 SRCD cursor C END -9- C SRCD IFGT SFLRN1 -A- Upper limit C MOVE SFLRN1 SRCD is number C END -A- of records C ENDSR C*-- Edit input fields for screen FM01. ------------* C FM01ED BEGSR C MOVEA'00000' *IN,11 Reset errors C MOVE *ALL'0' SFLM C MOVEA'100' *IN,91 Read changed C *IN92 DOWEQ'0' -1- subfile C READCFM01SFL 92 records C MOVEA'00' *IN,14 Reset errors C *IN92 IFEQ '0' -2- C SOBTX IFEQ *BLANKS -3- C MOVE '1' *IN14 C MOVE '1' SFLM,1 C *IN93 IFEQ '0' -4- Save RRN of C MOVE SFLRN1 SRCD 1st changed C MOVE '1' *IN93 record with C END -4- error C END -3- C UPDATFM01SFL C END -2- C END -1- C MOVEASFLM *IN,14 SFLMSG *IN's C MOVEA*IN,11 AF#005 5 C AF#005 IFNE *ALL'0' -5- If errors, C MOVE '1' *IN01 redisplay C END -5- C ENDSR C*-- Enter key processing. -------------------------* C FM0100 BEGSR C EXSR FM01ED C *IN01 IFEQ '0' -1- No errors C EXSR CHGTXT C END -1- C ENDSR C*-- F3=Exit. --------------------------------------* C FM0103 BEGSR C MOVE 'EXIT' NXTSCN Exit the C ENDSR program C*-- Change the Text for the selected objects. ------* C CHGTXT BEGSR C MOVE '0' *IN91 Read changed C *IN91 DOWEQ'0' -1- subfile C READCFM01SFL 91 records C *IN91 IFEQ '0' -2- C MOVE CMD,1 DSCMD Set up and C MOVE ODOBNM DSOBNM execute C MOVE ODOBTP DSOBTP CHGOBJD C MOVE SOBTX DSOBTX command C CALL 'QCMDEXC' 60 C* CALL 'QCAEXEC' 60 C PARM DSCMD C PARM 80 CMDLEN 155 C SFLRN1 CHAINQLIDOBJD 91 Update C MOVE SOBTX ODOBTX record C UPDATQLIDOBJD in QADSPOBJ C END -2- C END -1- C ENDSR C*-- Program initialization subroutine. ------------* C ZFIRST BEGSR C MOVE 'FM01' NXTSCN 4 Next screen C Z-ADD1 SRCD Subfile cursor C ENDSR C*-- Program exit subroutine. ----------------------* C ZEXIT BEGSR C MOVE *BLANKS NXTSCN Next screen C ENDSR ** CHGOBJD XXXXXXXXXX XXXXXXXX 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
Subfile Fundamentals
Figure 3C Display file SFL002DF
A* 90/09/10 11:55:49 ERNIE REL-R02M00 5728-PW1 A* A* SFL002DF - CHANGE OBJECT DESCRIPTIONS A* A DSPSIZ(24 80 *DS3) A REF(*LIBL/QADSPOBJ) A R FM01HDR A* 90/09/10 11:55:49 ERNIE REL-R02M00 5728-PW1 A 1 2DATE A EDTCDE(Y) A 1 11TIME A 1 22'OBJECT DESCRIPTION - *BASIC' A DSPATR(HI) A 1 74'SFL011' A R FM01SFL SFL A* 90/09/10 11:55:49 ERNIE REL-R02M00 5728-PW1 A 91 SFLNXTCHG A ODOBNM R O 6 4 A ODOBTP R O 6 15 A SOBTX R B 6 24REFFLD(ODOBTX) A CHECK(LC) A 14 DSPATR(RI) A R FM01CTL SFLCTL(FM01SFL) A CA03 A BLINK OVERLAY A SFLSIZ(0017) SFLPAG(0016) A N98 SFLDSP SFLDSPCTL SFLEND A 98 SFLCLR A 14 SFLMSG('Text must not be blank.') A 3 2'Position cursor at sequence:' A SRCD 4S 0B 3 31SFLRCDNBR(CURSOR) RANGE(1 9999) A 5 4'OBJECT' DSPATR(HI) A 5 15'TYPE' DSPATR(HI) A 5 24'TEXT' DSPATR(HI) A R FM01CK OVERLAY A 23 2'F3=Exit'
Subfile Fundamentals
Figure 4 Pseudocode for FM01BL subroutine
Figure 4: Pseudocode for FM01BL Subroutine Clear the subfile Reset subfile RRN to zero Position the database file While not EOF Read the database file If not EOF Move data fields as required Increment subfile RRN Write subfile record Endif EndWhile Initialize SFLRCDNBR field
Subfile Fundamentals
Figure 5 Pseudocode for FM01ED subroutine
Figure 5: Pseudocode for FM01ED Subroutine Set off elements 11-15 in the Indicator-array Set off elements 1-2 in the Save-indicator-array (Perform edits for SFLCTL fields which may set on Indicators 11-13) While not EOF-changed-records Set off elements 14-15 in the Indicator-array Read-change-records If not EOF-changed-records If Error-condition-1 Set on Inidcator-14 Set on Save-Indicator-1 Save RRN of first record with error Endif (If Error-condition-1 Set on Indicator-15 Set on Save-Indicator-2 Save RRN of first record with error Endif) Update subfile record Endif Endwhile Move Save-indicator-array to Indicator-array beginning with element 14 Move elements 11-15 of Indicator-array to Alpha-field-length-5 If Alpha-field-length-5 is not ALL-'0' Set on Re-display-indicator Endif
Subfile Fundamentals
Figure 6 Examploe of using CHAIN operation with a subfile
Figure 6: Example of Using the CHAIN Operation With a Subfile C* Write records to the transaction file C WRTRCD BEGSR C DO 15 SFLRN1 C SFLRN1 CHAINFM01SFL 90 C *IN90 IFEQ '0' C MOVE SITEM DITEM C MOVE SVEND DVEND C MOVE STRCD DTRCD C WRITETRANS C END C END C ENDSR
LATEST COMMENTS
MC Press Online