Wednesday, November 15, 2023

Another way to read a subfile

The idea for this post came from a question I was asked. I was asked to clarify an answer to a question someone was asked during a job interview. They had been asked was it possible to read a subfile without using the READC, read changed records, operation code? The interviewee answered that it could probably be read using a CHAIN operation. The interviewer told them they were wrong as it was not possible to use a CHAIN with a subfile.

The interviewee is correct. You can "read" a subfile using a CHAIN operation. This post demonstrates that is possible.

Before I start showing source code for a display file or RPG program, I am going to start with a DDS file I created:

01     A          R TESTFILER
02     A            NAME          20A
03     A          K NAME

I am sure none of you are surprised that I have called this file TESTFILE. It contains just one field, NAME, which is also the key for the file.

The file contains the following records:


I am going to create a modern RPG program to display these records in key order, and then CHAIN each subfile record.

Next I am going to show the display file, TESTDSPF. I have deliberately kept it very simple.

01   A                                      DSPSIZ(24 80 *DS3)
02   A                                      INDARA
03   A                                      REF(TESTFILEP)
04   A                                      CA03(03 'Exit')
05   A          R SFL01                     SFL
06   A            SFLRRN         4Y 0O  2  2EDTCDE(Z)
07   A            NAME      R        O  2  7
08   A          R CTL01                     SFLCTL(SFL01)
09   A                                      SFLSIZ(0100)
10   A                                      SFLPAG(0010)
11   A                                      OVERLAY
12   A  30                                  SFLDSP
13   A  30                                  SFLDSPCTL
14   A  30                                  SFLEND(*MORE)
15   A                                  1  2'Read subfile with CHAIN'
16   A                                      DSPATR(HI)

Lines 1 – 4: The file level keywords.

Line 1: These are the screen dimensions I want to display the record formats at.

Line 2: This is the indicator area. This allows me to share the indicator area with the RPG program.

Line 3: This is a file reference. This simplifies the way I can define fields in the display file, as I can use fields from the file to define fields in the display file.

Line 4: By using this I define that the F3 is used by this program, and will pass control back to the RPG program.

Lines 5 – 7: This is the definition of the subfile.

Line 6: This is the subfile relative record field. Normally this would be hidden, but I want it to be displayed in the subfile.

Line 7: This is the name field from TESTFILE. The "R" tells the compiler that this is field is referenced in TESTFILE, therefore, I do not need to give its type, length, etc. here.

Lines 8 – 17: This is the subfile control record format. I am not going to go into great detail about this as I am going to assume you have all written or worked with a subfile before.

Lines 9 and 10: The subfile has 100 records, and a maximum ten subfile records are displayed on each screen.

Lines 12 – 14: These are the various subfile control keywords, all need to have a conditioning indicator. I decided to use indicator 30.

Lines 15 and 16: This is the screen header for the subfile.

I have tried to keep the RPG code as simple as I can. I am going to show it in three parts: the main part, and the two subprocedures. Let me start with the main part.

01  **free
02  ctl-opt option(*nodebugio:*srcstmt) dftactgrp(*no) ;  

03  dcl-f TESTDSPF workstn indds(Dspf) sfile(SFL01:SFLRRN) ;

04  dcl-ds Dspf qualified ;
05    Exit ind pos(3) ;
06    SubfileDisplay ind pos(30) ;
07  end-ds ;

08  dcl-f TESTFILEP keyed ;

09  dcl-s SubfileMaximum int(10) ;

10  LoadSubfile() ;

11  dow (*on) ;
12    exfmt CTL01 ;

13    if (Dspf.Exit) ;
14      leave ;
15    else ;
16      ChainSubfile() ;
17    endif ;
18  enddo ;

19  *inlr = *on ;

Line 1: If I am writing RPG it is always totally free.

Line 2: My favorite control options, followed by DFTACTGRP(*NO) as this program contains subprocedures.

Line 3: File definition for the display file, TESTDSPF. As I used the indicator area in the display file I need to use INDDS to define what is the indicator array in the program.

Lines 4 – 7: The indicator array. As the display file only had two indicators, there are only two subfields.

Line 5: The RPG indicator Exit is mapped to indicator 3.

Line 6: Indicator SubfileDisplay is mapped to indicator 30.

Line 8: The definition of the input file, TESTFILE. It will be read in keyed order.

Line 9: Definition for a variable that will contain the count of the number of records written to the subfile.

Line 10: Call to the subprocedure to load the subfile. I use subprocedures rather than subroutines as I can define variables, files, data structures in a subprocedure rather than at the global, top of the program, level.

Lines 11 – 18: A never ending Do-loop used to display the subfile.

Line 12: I execute format the control record format to display it and the subfile.

Lines 13 and 14: If the F3 key is pressed on the display file the Do-loop is left.

Lines 15 and 16: If any other key is pressed the ChainSubfile subprocedure is called.

This is how I load the subfile from TESTFILE.

20  dcl-proc LoadSubfile ;
21    Dspf.SubfileDisplay = *on ;
22    SFLRRN = 0 ;

23    dow (*on) ;
24      read TESTFILER ;
25      if (%eof) ;
26        leave ;
27      endif ;

28      SFLRRN += 1 ;
29      write SFL01 ;
30    enddo ;

31    SubfileMaximum = SFLRRN ;
32  end-proc ;

Line 21: I need to set the subfile display indicators to "on" before I execute format the control record format.

Line 22: Each subfile record needs its own unique relative record number. Here I am setting the subfile relative record number field to zero.

Lines 23 – 29: A never ending Do-loop to read all the records in TESTFILE.

Lines 28 and 29: If it is not end of file for TESTFILE the subfile relative record number field is incremented, and then the subfile record is written.

Line 31: When all of the records have been written to the subfile I need to capture the number of the maximum relative record number for later use.

Onto the last subprocedure, which contains the reason for this post.

33  dcl-proc ChainSubfile ;
34    dcl-s Number int(10) ;

35    for Number = 1 to SubfileMaximum ;
36      chain Number SFL01 ;
37      dsply (%char(SFLRRN) + ' ' + NAME) ;
38    endfor ;
39  end-proc ;

Line 34: I define a variable to contain the increment count of subfile records.

Line 35: I am using a For-group to cycle through the subfile records.

Line 36: I use the variable Number to CHAIN the subfile.

Line 37: The Display operation code, DSPLY, displays the subfile relative record number and the name from the subfile record I retrieved with the CHAIN operation.

The program has been written. I compile it. Then I call it. First the subfile is displayed.

Read subfile with CHAIN
   1 ANNE
   2 BRYAN
   3 COLIN
   4 DAISY
   5 EDNA
   7 SIMON
   8 ZOE


When I press Enter the program's flow goes into the ChainSubfile subprocedure. In turn this displays the data from the subfile records I retrieved using the CHAIN.


I am returned to the subfile. I exit by pressing the F3 key.

This proves that you can "read" the subfile records using CHAIN. And the interviewer was wrong.


This article was written for IBM i 7.5, and should work for some earlier releases too.


  1. I guess the interviewer has never used SFLCSRRRN(&CURSOR) to chain to a subfile record either

  2. I wonder what answer the interviewer wanted to hear.

    1. The interviewee told me the interviewer got angry with them and told them you could only do this using READC.

  3. The interviewee gave a correct answer to the question they were asked. In practical terms, to retrieve all available subfile records via Chains would probably be less logical than via ReadC. Of course, it would all depend on the specific program logic.


To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.