Some RPG Sample Code

Subfiles

1. Example of "load all" subfile
Features:
  • "Load all" type subfile, max 9999 records
  • permits positioning and page down
  • fully RPGLE/free
  • F5 = refresh data from file
  • F11 = drop/fold second line
Show/Hide code

      // Program: SF_02
      // "Load All" type subfile, max 9999 records
      // this example permits positioning and page up/down
      // uses RPGLE/free
      // F5  = refresh data from file
      // F11 = drop/fold second line
      // inspired by:
      // https://www.rpgpgm.com/2016/05/example-subfile-program-using-modern-rpg.html
      //
      // Create a work file and populate with some data:
      //   CREATE TABLE MYLIB/ORDER_DET (
      //       DETAIL_NUM INT NOT NULL WITH DEFAULT,
      //       DETAIL_LIN INT NOT NULL WITH DEFAULT,
      //       DETAIL_SKU CHAR (25) NOT NULL WITH DEFAULT,
      //       DETAIL_QTY INT NOT NULL WITH DEFAULT,
      //       DETAIL_PRI DEC ( 10, 2) NOT NULL WITH DEFAULT
      //    )
      //    RCDFMT  ORDER_DETR
      //
      //    CREATE INDEX MYLIB/ORD_DETL1
      //      ON ORDER_DET(DETAIL_NUM, DETAIL_LIN)

       ctl-opt option(*nodebugio:*srcstmt:*nounref) dftactgrp(*no) ;

       dcl-f ORD_DETL1 keyed ;
       //dcl-f SF_02D workstn indds(Dspf) sfile(SFL01:Z1RRN) infds(InfDs1);
       dcl-f SF_02D workstn indds(Indds1) sfile(SFL01:Z1RRN) infds(InfDs1);

       // psds - Program Status Data Structure
       dcl-ds PgmDs psds qualified ;
           PgmName *proc ;
       end-ds ;

       // InfDs - File Information Data Structure
       dcl-ds InfDs1 qualified ;
           Choice    char(1) pos(369);
           Recno     int(5)  pos(378);
       end-ds ;

       dcl-ds Indds1 qualified ;
          Exit      ind pos(3)  ;
          Refresh   ind pos(5)  ;
          SflDspCtl ind pos(30) ;
          SflDsp    ind pos(31) ;
       end-ds ;

       dcl-s RecNo_H zoned(4:0) ;
       dcl-s PrvPos1 like(Z1POS1) ;
       dcl-s PrvPos2 like(Z1POS2) ;
       dcl-c MaxSfl 9999 ;

       // -----------------------------------------------------------------------

       Init();
       LoadSubfile() ;

        dow ( Indds1.Exit = *off);
          write FOOTER;
          exfmt CTL01 ;
          eval RecNo_H = InfDs1.Recno;

          if (Indds1.Exit) ;
            leave ;
          elseif (Indds1.Refresh) ;
            Z1POS1 = 0  ;
            Z1POS2 = 0  ;
            PrvPos1 = 0   ;
            PrvPos2 = 0   ;
            setll *loval ORDER_DETR;
            LoadSubfile() ;
            iter ;
          elseif (Z1POS1 <> PrvPos1 or Z1POS2 <> PrvPos2);
            PrvPos1 = Z1POS1 ;
            PrvPos2 = Z1POS2 ;
            setll (Z1POS1:Z1POS2) ORDER_DETR;
            loadSubfile() ;
            iter ;
          endif ;

          if (Indds1.SflDsp) ;
            readSubfile() ;
          endif ;
        enddo ;

        *inlr = *on ;

        // ---------------------------------------------------------------------
        dcl-proc LoadSubfile ;
          Indds1.SflDspCtl = *off ;
          Indds1.SflDsp = *off ;
          eval RecNo_H = 1;
          write CTL01 ;
          Indds1.SflDspCtl = *on ;

          Z1OPT = ' ' ;

          for Z1RRN = 1 to MaxSfl ;
            read ORDER_DETR;
            if (%eof) ;
              leave ;
            endif ;

            write SFL01 ;
          endfor ;

          if (Z1RRN > 1) ;
            Indds1.SflDsp = *on ;
          endif ;
        end-proc ;

        // ---------------------------------------------------------------------
        dcl-proc ReadSubfile ;
         dow (1 = 1) ;
            readc SFL01 ;
            if (%eof) ;
              leave ;
            endif ;
              //Do something depending on value in Z1OPT
            Dsply  Z1OPT;
            Z1OPT = ' ' ;
            update SFL01 ;
          enddo ;
        end-proc ;
        // ---------------------------------------------------------------------
        dcl-proc Init ;
          Z1SCREEN = %trimr(PgmDs.PgmName) + '-1' ;
        end-proc ;
     A                                      DSPSIZ(24 80 *DS3)
     A                                      REF(*LIBL/ORDER_DET)
     A                                      PRINT
     A                                      INDARA
     A                                      CA03(03 'F3=Exit')
     A* ---------------------------------------------------------------------
     A* SubFile Record
     A          R SFL01                     SFL
     A            Z1RRN          4S 0H
     A            Z1OPT          1A  B  5  3
     A            DETAIL_NUMR     Y  O  5  6REFFLD(DETAIL_NUM)
     A                                      EDTCDE(4)
     A            DETAIL_LINR     Y  O  5 24REFFLD(DETAIL_LIN)
     A                                      EDTCDE(4)
     A            DETAIL_SKUR        O  6 10REFFLD(DETAIL_SKU)
     A* ---------------------------------------------------------------------
     A* Control Record
     A          R CTL01                     SFLCTL(SFL01)
     A                                      SFLSIZ(09)
     A                                      SFLPAG(08)
     A                                      OVERLAY
     A  31                                  SFLDSP
     A  30                                  SFLDSPCTL
     A N30                                  SFLCLR
     A  30                                  SFLEND(*MORE)
     A N77                                  SFLDROP(CF11)
     A  77                                  SFLFOLD(CF11)
     A                                      CA05(05 'F5=Refresh')
     A                                      CF11(11 'F11=Fold')
     A* Use value in SFLRCDNBR to ensure that we don't loop back to first page at end of subfile
     A            RECNO_H        4S 0H      SFLRCDNBR
     A                                  1  2USER
     A                                      COLOR(BLU)
     A                                  1 63TIME
     A                                      COLOR(BLU)
     A                                  1 72DATE
     A                                      EDTCDE(Y)
     A                                      COLOR(BLU)
     A            Z1SCREEN      12A  O  2  2COLOR(BLU)
     A                                  2 72SYSNAME
     A                                      COLOR(BLU)
     A                                  3  2'Position to:'
     A                                      COLOR(BLU)
     A            Z1POS1    R        B  3 15REFFLD(DETAIL_NUM)
     A                                      COLOR(BLU)
     A            Z1POS2    R        B  3 26REFFLD(DETAIL_LIN)
     A                                      COLOR(BLU)
     A                                  4  7'Order No'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  4 26'Line No'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  1 21'Order Detail Screen'
     A* ---------------------------------------------------------------------
     A          R FOOTER
     A                                 23  2'F3=Exit'
     A                                      COLOR(BLU)
     A                                 23 12'F5=Refresh'
     A                                      COLOR(BLU)
     A                                 23 25'F11=Fold'
     A                                      COLOR(BLU)

Sample output:

USERNAME                                                    21:05:44 11/13/21
 SF_02-1                                                             SYS_NAME  
      Position to: _________ ________                        
     Order No           Line No                                                
          100                 1                                                
    ABCD12345678901234567890                                                   
          100                 2                                                
    ABCD12345678901234567891                                                   
          101                 1                                                
    ABCD12345678901234567892                                                   
          101                 2                                                
    ABCD12345678901234567893                                                   
          102                 1                                                
    ABCD12345678901234567894                                                   
          102                 2                                                
    ABCD12345678901234567895                                                   
          105                 1                                                
    ABCD12345678901234567896                                                   
          105                 2                                                
    ABCD12345678901234567897                                                   
                                                                       More... 
                                                                               
 F3=Exit   F5=Refresh     F11=Drop/Fold                                                       
2. Example of screen at a time subfile
Features:
  • subfile: load one page at a time
  • record positioning and page up/down
  • entirely RPGLE/free
Show/Hide code

      // Program: SF_03
      // load page at a time subfile
      // this example permits positioning and page up/down
      // uses RPGLE/free
      // F5  = refresh data from file
      // inspired by:
      // https://www.rpgpgm.com/2016/05/example-subfile-program-using-modern-rpg.html
      //
      // Create a work file and populate with some data:
      //   CREATE TABLE MYLIB/ORDER_DET (
      //       DETAIL_NUM INT NOT NULL WITH DEFAULT,
      //       DETAIL_LIN INT NOT NULL WITH DEFAULT,
      //       DETAIL_SKU CHAR (25) NOT NULL WITH DEFAULT,
      //       DETAIL_QTY INT NOT NULL WITH DEFAULT,
      //       DETAIL_PRI DEC ( 10, 2) NOT NULL WITH DEFAULT
      //    )
      //    RCDFMT  ORDER_DETR
      //
      //    CREATE INDEX MYLIB/ORD_DETL1
      //      ON ORDER_DET(DETAIL_NUM, DETAIL_LIN)

       ctl-opt option(*nodebugio:*srcstmt:*nounref)
               dftactgrp(*no) ;

       dcl-f ORD_DETL1 keyed ;

       dcl-f SF_03D  workstn indds(Indds1) sfile(SFL01:ZRRN) ;

       dcl-ds Indds1 qualified ;
           Exit      ind     pos(3)  ;
           Drop      ind     pos(11) ;
           PageDown  ind     pos(25) ;
           PageUp    ind     pos(26) ;
           SflInds   char(4) pos(30) ;
           SflDspCtl ind     pos(30) ;
           SflDsp    ind     pos(31) ;
           SflEnd    ind     pos(32) ;
           SflClr    ind     pos(33) ;
       end-ds ;

       dcl-ds PgmDs psds qualified ;
           PgmName *proc ;
       end-ds ;

       dcl-s SflSize like(ZRRN) inz(16) ;
       dcl-s PrvPos1 like(Z1POS1) ;
       dcl-s PrvPos2 like(Z1POS2) ;

       //-------------------------------------------------------

       Init();
       SubfileDown() ;

        dow not(Indds1.Exit) ;
         write FOOT01 ;
         exfmt CTL01 ;

         // page down
         if (Indds1.PageDown) ;
          if not(Indds1.SflEnd) ;
            SubfileDown() ;
          endif ;

         // page up
         elseif (Indds1.PageUp) ;
           SubfileUp() ;

          elseif (Z1POS1 <> PrvPos1 or Z1POS2 <> PrvPos2);
           setll (Z1POS1:Z1POS2) ORDER_DETR;
           SubfileDown() ;
           PrvPos1 = Z1POS1 ;
           PrvPos2 = Z1POS2 ;
          endif ;
          if (Indds1.SflDsp) ;
            ReadSubfile() ;
          endif ;
        enddo ;
        *inlr = *on ;

        //-------------------------------------------------------
        dcl-proc SubfileDown ;
         Indds1.SflInds = '0001' ;
         write CTL01 ;
         Indds1.SflInds = '1000' ;
         for ZRRN = 1 to SflSize ;
           read ORDER_DETR;
           if (%eof) ;
             Indds1.SflEnd = *on ;
             leave ;
           endif ;
           write SFL01 ;
         endfor ;
         if (ZRRN > 1) ;
           Indds1.SflDsp = *on ;
         else ;
           return ;
         endif ;

         if not(Indds1.SflEnd) ;
           read ORDER_DETR;
           if (%eof) ;
            Indds1.SflEnd = *on ;
           else ;
             setll (DETAIL_NUM:DETAIL_LIN) ORDER_DETR;
           endif ;
         endif ;
       end-proc;

       //-------------------------------------------------------
       dcl-proc SubfileUp ;
        chain 1 SFL01 ;
        setll (DETAIL_NUM:DETAIL_LIN) ORDER_DETR;
        for ZRRN = 1 to SflSize ;
          readp ORDER_DETR;
          if (%eof) ;
            leave ;
          endif ;
        endfor ;
        setll (DETAIL_NUM:DETAIL_LIN) ORDER_DETR;
        SubfileDown() ;
       end-proc;

        // ---------------------------------------------------------------------
        dcl-proc ReadSubfile ;
         dow (1 = 1) ;
            readc SFL01 ;
            if (%eof) ;
              leave ;
            endif ;
              //Do something depending on value in Z1OPT
            Dsply  Z1OPT;
            Z1OPT = ' ' ;
            update SFL01 ;
          enddo ;
        end-proc ;
        // ---------------------------------------------------------------------
        dcl-proc Init ;
          Z1SCREEN = %trimr(PgmDs.PgmName) + '-1' ;
        end-proc ;
DDS:
     A                                      DSPSIZ(24 80 *DS3)
     A                                      REF(*LIBL/ORDER_DET)
     A                                      PRINT
     A                                      INDARA
     A                                      CA03(03 'F3=Exit')
     A* SubFile Record
     A*
     A          R SFL01                     SFL
     A            ZRRN           2S 0H
     A            Z1OPT          1A  B  5  3
     A            DETAIL_NUMR     Y  O  5  6REFFLD(DETAIL_NUM)
     A                                      EDTCDE(4)
     A            DETAIL_LINR     Y  O  5 24REFFLD(DETAIL_LIN)
     A                                      EDTCDE(4)
     A            DETAIL_SKUR        O  5 41REFFLD(DETAIL_SKU)

     A* Control Record
     A*
     A          R CTL01                     SFLCTL(SFL01)
     A                                      SFLSIZ(0016)
     A                                      SFLPAG(0016)
     A                                      OVERLAY
     A                                      PAGEDOWN(25)
     A                                      PAGEUP(26)
     A  30                                  SFLDSPCTL
     A  31                                  SFLDSP
     A  32                                  SFLEND(*MORE)
     A  33                                  SFLCLR
     A            Z1SCREEN      12A  O  2  2COLOR(BLU)
     A                                  2 72SYSNAME
     A                                      COLOR(BLU)
     A                                  3  2'Position to'
     A            Z1POS1    R        B  3 15REFFLD(DETAIL_NUM)
     A                                      COLOR(BLU)
     A            Z1POS2    R        B  3 26REFFLD(DETAIL_LIN)
     A                                      COLOR(BLU)
     A                                  4  7'Order No'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  4 26'Line No'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  4 41'SKU No'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  1 21'Order Detail Screen'

     A          R FOOT01
     A                                 23  3'F3=Exit'

3. Example of program with two subfiles (header/detail drilldown)
Features:
  • subfile: load one page at a time
  • record positioning and page up/down
  • uses 2 subfiles (show headers, drill through to details) - one procedure per subfile
Show/Hide code

      // Program: SF_05
      // a work in progress...
      // load page at a time subfile
      // uses 2 subfiles (show headers, drill through to details) - one procedure per subfile
      // uses RPGLE/free
      //
      // Create a Order header and detail tables, indexes, then add some data.
      //
      //    CREATE TABLE MYLIB/ORDER_HED (
      //      ORDER_NUM INT NOT NULL WITH DEFAULT,
      //      ORDER_CUST INT NOT NULL WITH DEFAULT,
      //      ORDER_DATE DATE NOT NULL WITH DEFAULT,
      //      ORDER_TIME TIME NOT NULL WITH DEFAULT,
      //      ORDER_VALUE DEC ( 11, 2) NOT NULL WITH DEFAULT
      //    )
      //    RCDFMT  ORDER_HEDR
      //
      //   CREATE TABLE MYLIB/ORDER_DET (
      //       DETAIL_NUM INT NOT NULL WITH DEFAULT,
      //       DETAIL_LIN INT NOT NULL WITH DEFAULT,
      //       DETAIL_SKU CHAR (25) NOT NULL WITH DEFAULT,
      //       DETAIL_QTY INT NOT NULL WITH DEFAULT,
      //       DETAIL_PRI DEC ( 10, 2) NOT NULL WITH DEFAULT
      //    )
      //    RCDFMT  ORDER_DETR
      //
      //  Indexes:
      //
      //    CREATE INDEX MYLIB/ORD_DETL1
      //      ON ORDER_DET(DETAIL_NUM, DETAIL_LIN)
      //
      //    CREATE INDEX MYLIB/ORD_HEDL1
      //      ON MYLIB/ORDER_HED (ORDER_NUM)

       ctl-opt option(*nodebugio:*srcstmt:*nounref)
               dftactgrp(*no);

       dcl-pr  ProcessSubfile2  char(1) ;
       End-pr ;

       dcl-f ORD_HEDL1 keyed ;
       dcl-f ORD_DETL1 keyed ;

       dcl-f SF_05D  workstn indds(Indds) sfile(SFL01:Z1RRN)
                             infds(infds1) sfile(SFL02:Z2RRN) ;

       dcl-ds Indds qualified ;
           Exit      ind     pos(3)  ;      // F3
           Drop      ind     pos(11) ;
           ReturnF12 ind     pos(12) ;      // F12
           PageDown  ind     pos(25) ;
           PageUp    ind     pos(26) ;
           SflInds   char(4) pos(30) ;
           SflDspCtl ind     pos(30) ;
           SflDsp    ind     pos(31) ;
           SflEnd    ind     pos(32) ;
           SflClr    ind     pos(33) ;
           Refresh   ind     pos(77) ;
       end-ds ;

       // backup for Indds
       dcl-ds Indds_bk likeds(Indds);

       dcl-ds PgmDs psds qualified ;
           PgmName *proc ;
       end-ds ;

       dcl-ds infds1 qualified ;
          KeyPressed   char(1)  pos(369);
       end-ds ;

       dcl-s PrvPos1 like(Z1POS1) ;
       dcl-s show_subfile char(1);

       dcl-c EnterKey    const(x'F1');
       dcl-c F1Key       const(x'31');
       dcl-c F3Key       const(x'33');
       dcl-c F5Key       const(x'35');
       dcl-c F12Key      const(x'3C');

       //-------------------------------------------------------
          ProcessSubfile1();
          *inlr = *on ;
       //-------------------------------------------------------

        //-------------------------------------------------------
        // SUBFILE 1
        //-------------------------------------------------------
        dcl-proc ProcessSubfile1;

          dcl-s myKeypressed char(1);
          dcl-s SflSize1 like(Z1RRN) inz(14) ;

          exsr Init;
          exsr SubfileDown1 ;
          dow not(Indds.Exit) and not(Indds.ReturnF12);
           write FOOT01 ;
           exfmt CTL01 ;

           // page down
           if (Indds.PageDown) ;
            if not(Indds.SflEnd) ;
              Exsr SubfileDown1;
            endif ;

           // page up
           elseif (Indds.PageUp) ;
             Exsr SubfileUp1 ;

           // position to
            elseif (Z1POS1 <> PrvPos1);
             setll (Z1POS1) ORDER_HEDR;
             Exsr SubfileDown1 ;
             PrvPos1 = Z1POS1 ;

            // refresh
            elseif (Indds.Refresh) ;
               setll *loval ORDER_HEDR;
               Exsr Init;
               exsr SubfileDown1 ;
               iter ;
            endif;

            if (Indds.SflDsp) ;
              Exsr ReadSubfile1 ;
              if (Indds.Exit);
                 Leave;
              endif ;
            endif ;
          enddo ;

          //-------------------------------------------------------
          begsr  WriteControlRec1     ;
            Indds.SflDspCtl   = *Off  ;
            Indds.SflDsp      = *Off  ;
             Indds.SflEnd     = *Off  ;
            Indds.SflClr      = *On   ;
            write CTL01               ;
            Indds.SflDspCtl   = *On   ;
            Indds.SflClr      = *Off  ;
          endsr;
        //-------------------------------------------------------
          begsr    SubfileDown1 ;
            Exsr WriteControlRec1;
            for Z1RRN = 1 to SflSize1 ;
              read ORDER_HEDR;
              if (%eof) ;
                Indds.SflEnd = *on ;
                leave ;
              endif ;
              write SFL01 ;
            endfor ;

         // if records found, then display on
         if (Z1RRN > 1) ;
           Indds.SflDsp = *on ;
         else ;
           Indds.SflDsp = *off ;
         endif ;

         //if not(Indds.SflEnd) ;
         //  read ORDER_HEDR;
         //  if (%eof) ;
         //   Indds.SflEnd = *on ;
         //  else ;
         //    setll (ORDER_NUM) ORDER_HEDR;
         //  endif ;
         //endif ;
        endsr;

         //-------------------------------------------------------
         begsr    SubfileUp1 ;
          chain 1 SFL01 ;
          setll (ORDER_NUM) ORDER_HEDR ;
          for Z1RRN = 1 to SflSize1 ;
            readp ORDER_HEDR;
            if (%eof) ;
              leave ;
            endif ;
          endfor ;
          setll (ORDER_NUM) ORDER_HEDR;
          Exsr SubfileDown1 ;
         endsr;

          // ---------------------------------------------------------------------
          // Read subfile and perform appropriate actions
          // ---------------------------------------------------------------------
          begsr ReadSubfile1;
           dow (1 = 1) ;
            readc SFL01 ;
            if (%eof) ;
              leave ;
            endif ;
              //Do something depending on value in Z1OPT
            select;
              when Z1OPT = '1' or Z1OPT = '2';
                Exsr Init;
                Eval Indds_bk = Indds ;
                myKeypressed = ProcessSubfile2() ;

                if myKeyPressed =  F12Key;
                   Eval myKeyPressed = *blanks;
                   Eval Indds = Indds_bk ;    // back to screen1
                   Eval Indds.ReturnF12 = *off;
                endif;

                if myKeyPressed =  F3Key;
                   Eval Indds = Indds_bk ;    // back to screen1
                   Return;
                endif;

                when Z1OPT = '7';
                  // delete record
                other;
                  Eval Z1OPT = Z1OPT;
              endsl;
                Z1OPT = ' ' ;
                update SFL01 ;
           enddo ;
          endsr;
          //-------------------------------------------------------
          begsr Init;
            Z1SCREEN = %trimr(PgmDs.PgmName) + '-1';
            Z1POS1 = 0;
            PrvPos1 = 0;
          endsr;

        end-proc;
        //-------------------------------------------------------
        // SUBFILE 2
        //-------------------------------------------------------
        dcl-proc ProcessSubfile2;

          dcl-pi  ProcessSubfile2  char(1)   ;
          end-pi                             ;

          dcl-s SflSize2 like(Z2RRN) inz(14) ;

          exsr Init;
          //dcl-s Keypressed    char(1);
          setll (ORDER_NUM) ORDER_DETR;

          Exsr SubfileDown2 ;
          dow (1=1);
           write FOOT01 ;
           exfmt CTL02 ;
           If  infds1.Keypressed = F3Key or
               infds1.Keypressed = F12Key;
               return infds1.Keypressed;
           Endif;

           // page down
           if (Indds.PageDown) ;
            if not(Indds.SflEnd) ;
              Exsr SubfileDown2;
            endif ;

           // page up
           elseif (Indds.PageUp) ;
             Exsr SubfileUp2 ;

            elseif (Z1POS1 <> PrvPos1);
             setll (Z1POS1) ORDER_HEDR;
             Exsr SubfileDown2 ;
             PrvPos1 = Z1POS1 ;

            // refresh
            elseif (Indds.Refresh) ;
               setll *loval ORDER_HEDR;
               Exsr Init;
               Exsr SubfileDown2 ;
               iter ;
            endif;
            if (Indds.SflDsp) ;
              exsr ReadSubfile2 ;
            endif ;
          enddo ;

          //-------------------------------------------------------
          begsr WriteControlRec2     ;
             Indds.SflDspCtl   = *Off  ;
             Indds.SflDsp      = *Off  ;
             Indds.SflEnd      = *Off  ;
             Indds.SflClr      = *On   ;
             write CTL02                ;
             Indds.SflDspCtl   = *On   ;
             Indds.SflClr      = *Off  ;
         endsr;

          //-------------------------------------------------------
          begsr SubfileDown2 ;
          Exsr WriteControlRec2;
           for Z2RRN = 1 to SflSize2;
             reade (ORDER_NUM) ORDER_DETR;
             if (%eof) ;
               Indds.SflEnd = *on ;
             leave ;
             endif ;
             write SFL02 ;
           endfor ;
           if (Z2RRN > 1) ;
             Indds.SflDsp = *on ;
           else ;
             Indds.SflDsp = *off ;
           endif ;

           if not(Indds.SflEnd) ;
             reade (ORDER_NUM) ORDER_DETR;
             if (%eof) ;
              Indds.SflEnd = *on ;
             else ;
               setll (DETAIL_NUM) ORDER_DETR;
             endif ;
           endif ;
         endsr;

         //-------------------------------------------------------
         begsr SubfileUp2 ;
          chain 1 SFL02 ;
          setll (DETAIL_NUM) ORDER_DETR;
          for Z2RRN = 1 to SflSize2 ;
            readpe (ORDER_NUM) ORDER_DETR;
            if (%eof) ;
              leave ;
            endif ;
          endfor ;
          setll (ORDER_NUM) ORDER_DETR;
          Exsr SubfileDown2 ;
         endsr;

          // ---------------------------------------------------------------------
          begsr ReadSubfile2;
           dow (1 = 1) ;
              readc SFL02 ;
              if (%eof) ;
                leave ;
              endif ;
              //Do something depending on value in Z1OPT
              Dsply  Z1OPT;
              Z1OPT = ' ' ;
              update SFL02 ;
            enddo ;
          endsr;
          // ---------------------------------------------------------------------
          begsr Init;
            Z2SCREEN = %trimr(PgmDs.PgmName) + '-2';
            Z1POS1 = 0;
            PrvPos1 = 0;
          endsr;

        end-proc;
        // ---------------------------------------------------------------------

DDS:
     A* DDS SCREEN FILE: SF_05D
     A                                      DSPSIZ(24 80 *DS3)
     A                                      REF(*LIBL/ORDER_DET)
     A                                      PRINT
     A                                      INDARA
     A                                      CA03(03 'F3=Exit')
     A                                      CA12(12 'F12=Return')
     A* SubFile Record
     A*
     A          R SFL01                     SFL
     A            Z1RRN          2S 0H
     A            Z1OPT          1A  B  7  3
     A            ORDER_NUM      9Y 0O  7  6
     A                                      EDTCDE(4)
     A            ORDER_CUST     9Y 0O  7 24
     A                                      EDTCDE(4)
     A            ORDER00001    11  2O  7 41
     A                                      EDTCDE(4)

     A* Control Record
     A*
     A          R CTL01                     SFLCTL(SFL01)
     A*%%TS  SD  20250315  223304  TORONTO22   REL-V7R5M0  5770-WDS
     A                                      SFLSIZ(0014)
     A                                      SFLPAG(0014)
     A                                      OVERLAY
     A                                      PAGEDOWN(25)
     A                                      PAGEUP(26)
     A  30                                  SFLDSPCTL
     A  31                                  SFLDSP
     A  32                                  SFLEND(*MORE)
     A  33                                  SFLCLR
     A                                      CA05(05 'F5=Refresh')
     A                                      CF11(11 'F11=Fold')
     A            Z1SCREEN      12A  O  2  2COLOR(BLU)
     A                                  2 72SYSNAME
     A                                      COLOR(BLU)
     A                                  3  2'Position to'
     A            Z1POS1        11S 0B  3 15COLOR(BLU)
     A            Z1POS2        11S 0B  3 26COLOR(BLU)
     A                                  4  2'Actions: 1=View'
     A                                      COLOR(BLU)
     A                                  4 19'2=Edit  7=Delete'
     A                                      COLOR(BLU)
     A                                  5  7'Order No'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  5 26'Customer'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  5 41'Amount'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  1 21'Order Header Screen'
     A          R FOOT01
     A                                 23  3'F3=Exit F12=Return'
     A* SubFile Record
     A*
     A          R SFL02                     SFL
     A            Z2RRN          2S 0H
     A            Z2OPT          1A  B  7  3
     A            DETAIL_NUMR     Y  O  7  6REFFLD(DETAIL_NUM)
     A                                      EDTCDE(4)
     A            DETAIL_LINR     Y  O  7 17REFFLD(DETAIL_LIN)
     A            DETAIL_SKUR        O  7 29REFFLD(DETAIL_SKU)


     A* Control Record
     A*
     A          R CTL02                     SFLCTL(SFL02)
     A                                      SFLSIZ(0014)
     A                                      SFLPAG(0014)
     A                                      OVERLAY
     A                                      PAGEDOWN(25)
     A                                      PAGEUP(26)
     A  30                                  SFLDSPCTL
     A  31                                  SFLDSP
     A  32                                  SFLEND(*MORE)
     A  33                                  SFLCLR
     A*N77                                  SFLDROP(CF11)
     A* 77                                  SFLFOLD(CF11)
     A                                      CA05(05 'F5=Refresh')
     A                                      CF11(11 'F11=Fold')
     A            Z2SCREEN      12A  O  2  2COLOR(BLU)
     A                                  2 72SYSNAME
     A                                      COLOR(BLU)
     A                                  3  2'Position to'
     A            Z2POS1    R        B  3 15REFFLD(DETAIL_NUM)
     A                                      COLOR(BLU)
     A            Z2POS2    R        B  3 26REFFLD(DETAIL_LIN)
     A                                      COLOR(BLU)
     A                                  1 21'Order Detail Screen'
     A                                  4  2'Actions: 1=View'
     A                                      COLOR(BLU)
     A                                  4 19'2=Edit  7=Delete'
     A                                      COLOR(BLU)
     A                                  5  7'Order No'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  5 29'SKU'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  5 22'Line'
     A                                      DSPATR(UL)
     A                                      COLOR(WHT)
     A          R FOOT02
     A                                 23  3'F3=Exit F12=Return'
4. Example of program with subfile and second screen for edit
Features:
  • subfile: load one page at a time
  • record positioning and page up/down
  • permits view/edit/delete
  • uses DDS Window screen for view/edit
  • edit with simple error message
Show/Hide code

        // Program: SF_07
        // a work in progress
		// load page at a time subfile
        // this example permits positioning and page up/down
        // permits view/edit/delete 
        // edit with simple error message
		//
        // Create order detail table, indexes, then add some data.
        //
        //   CREATE TABLE MYLIB/ORDER_DET (
        //       DETAIL_NUM INT NOT NULL WITH DEFAULT,
        //       DETAIL_LIN INT NOT NULL WITH DEFAULT,
        //       DETAIL_SKU CHAR (25) NOT NULL WITH DEFAULT,
        //       DETAIL_QTY INT NOT NULL WITH DEFAULT,
        //       DETAIL_PRI DEC ( 10, 2) NOT NULL WITH DEFAULT
        //    )
        //    RCDFMT  ORDER_DETR
        //
        //  Indexes:
        //
        //    CREATE INDEX MYLIB/ORD_DETL1
        //      ON ORDER_DET(DETAIL_NUM, DETAIL_LIN)

        ctl-opt option(*nodebugio:*srcstmt:*nounref)  dftactgrp(*no) ;

        dcl-f ORD_DETL1 disk keyed
                        usage(*input: *update: *output: *delete);

        dcl-f SF_07D workstn indds(Indds) infds(InfDs) sfile(SFL01:Z1RRN) ;

        dcl-ds Indds qualified ;
            Exit      ind     pos(3)  ;
            Drop      ind     pos(11) ;  //note: cannot use drop/fold when SFLSIZ=SFLPAG
            Return12  ind     pos(12) ;
            PageDown  ind     pos(25) ;
            PageUp    ind     pos(26) ;
            SflDspCtl ind     pos(30) ;
            SflDsp    ind     pos(31) ;
            SflEnd    ind     pos(32) ;
            SflClr    ind     pos(33) ;
            RecView   ind     pos(50) ;
            RecEdit   ind     pos(51) ;
            RecAdd    ind     pos(52) ;
            Refresh   ind     pos(77) ;
        end-ds ;

        dcl-ds InfDs qualified ;
             KeyPress  char(1) pos(369);
        end-ds ;

        dcl-ds PgmDs psds qualified ;
            PgmName *proc ;
        end-ds ;

        // constants
        dcl-c true  const(*on);
        dcl-c false const(*off);

        // FunctionKey values (in hex)
        dcl-c EnterKey  const(x'F1');
        dcl-c F06 const(x'36');

        // variables
        dcl-s SflSize like(Z1RRN) inz(16) ;  // if changed, must change in DDS as well
        dcl-s SflPage like(Z1RRN) inz(16) ;
        dcl-s PrvPos1 like(Z1POS1) ;    // position to variable 1
        dcl-s PrvPos2 like(Z1POS2) ;    // position to variable 2
        dcl-s ACTION char(20);
        dcl-s Error ind;
        dcl-s redisplay_sfl char(1);

        //-------------------------------------------------------

        Init();
        ProcessSubfile1();
        *inlr = *on ;
        Return;

        //-------------------------------------------------------
        dcl-proc ProcessSubfile1;

          SubfileDown1() ;
          dow not(Indds.Exit) ;
           write dummy ;
           write Header01 ;
           write Footer01 ;
           exfmt CTL01 ;

           // page down
           if (Indds.PageDown) ;
            if not(Indds.SflEnd) ;
              SubfileDown1();
            endif ;

           // page up
           elseif (Indds.PageUp) ;
             SubfileUp1() ;

           // add record (F6)
           elseif (InfDs.KeyPress = F06);
              // to do
              RecordAdd();

           // re-position subfile
            elseif ((Z1POS1 <> PrvPos1) or (Z1POS2 <> PrvPos2));
             setll (Z1POS1:Z1POS2) ORDER_DETR;
             SubfileDown1() ;
             PrvPos1 = Z1POS1 ;
             PrvPos2 = Z1POS2 ;

            // refresh
            elseif (Indds.Refresh) ;
               setll *loval ORDER_DETR;
               Init();
               SubfileDown1() ;
               iter ;
            endif;
             if (Indds.SflDsp) ;
               ReadSubfile() ;
             endif ;
          enddo ;
        end-proc;

        //-------------------------------------------------------
        dcl-proc WriteControlRec1     ;
           Indds.SflDspCtl   = *Off  ;
           Indds.SflDsp      = *Off  ;
           Indds.SflEnd      = *Off  ;
           Indds.SflClr      = *On   ;
           write CTL01                ;
           Indds.SflDspCtl   = *On   ;
           Indds.SflClr      = *Off  ;
        end-proc;
        //-------------------------------------------------------
        // Read down table and write data to subfile
        //-------------------------------------------------------
        dcl-proc SubfileDown1 ;
          WriteControlRec1();
           for Z1RRN = 1 to SflSize ;
             read ORDER_DETR;
             if (%eof) ;
               Indds.SflEnd = *on ;
               leave ;
             endif ;
             write SFL01 ;
           endfor ;
           if (Z1RRN > 1) ;
             Indds.SflDsp = *on ;
           else ;
             return ;
           endif ;

        end-proc;

          //-------------------------------------------------------
          // Page up
          //-------------------------------------------------------
        dcl-proc SubfileUp1 ;
           chain 1 SFL01 ;
           setll (DETAIL_NUM: DETAIL_LIN) ORDER_DETr;
           for Z1RRN = 1 to SflSize ;
             readp ORDER_DETR;
             if (%eof) ;
               leave ;
             endif ;
           endfor ;
           setll (DETAIL_NUM: DETAIL_LIN) ORDER_DETR;
           SubfileDown1() ;
        end-proc;

          // ---------------------------------------------------------------------
          // Read through current subfile page and act on user input
          // ---------------------------------------------------------------------
        dcl-proc ReadSubfile ;
           Eval redisplay_sfl = 'N';
           dow (1 = 1) ;
             Eval Indds.recView = false;
             Eval Indds.recEdit = false;
             Eval Indds.recAdd  = false;
              readc SFL01 ;
              if (%eof) ;
                leave ;
              endif ;
                // Act on user inpu in option field (Z1OPT)
              select;
                when Z1OPT = '1';
                  View_Record();
                  Eval redisplay_sfl = 'N';
                when Z1OPT = '2';
                  Edit_Record();
                  Eval redisplay_sfl = 'Y';
                when Z1OPT = '4';
                  Delete_Record();
                  Eval redisplay_sfl = 'Y';
                other;
                  Eval Z1OPT = Z1OPT;
              endsl;
                Z1OPT = ' ' ;
                update SFL01 ;
            enddo ;

            //If there was delete, add or modify then reload page
            If redisplay_sfl ='Y';
              setll (Z1POS1:Z1POS2) ORDER_DETR;
              ACTION = 'SCREEN1';
              SubfileDown1();
            Endif;
        end-proc ;
        //------------------------------------------------------------------------
        // Edit on detail record
        //------------------------------------------------------------------------
        dcl-proc Edit_Record;

              Eval *IN10 = *off;      // SFL Display
              Eval Z2SCREEN = %trimr(PgmDs.PgmName) + '-2';              
              Eval Indds.recEdit = true;

              Dow not(Indds.Exit) and not(Indds.Return12) ;

                //Write Detail;
                If (Error = false);
                  Eval S_SKU = DETAIL_SKU;
                EndIf;
                Exfmt Window02;

                // Press enter to validate/update
                If  InfDs.KeyPress = EnterKey and
                   DETAIL_SKU <> S_SKU;
                   ValidateRecord();
                   If Error = *Off;
                     UpdateRecord();
                     Eval Indds.Return12 = *on;
                   EndIf;
                EndIf;

              // F12= Return
              If Indds.Return12;
                Eval Indds.Return12 = *off;
                ACTION = 'SCREEN1';
                LEAVE;
              EndIf;

              Enddo;

          end-proc;
        //-------------------------------------------------------
        // View record
        //------------------------------------------------------------------------
          dcl-proc View_Record;

              Eval *IN10 = *off;      // SFL Display              

              Eval  Indds.RecView = true;

              Dow not(Indds.Exit) and not(Indds.Return12) ;

                Eval S_SKU = DETAIL_SKU;
                Exfmt Window02;

                // Press enter to validate/update
                If  InfDs.KeyPress = EnterKey;
                   Eval Indds.Return12 = *on;
                EndIf;

              // F12= Return
              If Indds.Return12;
              //  Eval Indds.Return12 = *off;
              //  ACTION = 'SCREEN1';
              //  LEAVE;
              EndIf;

              Enddo;

          end-proc;
          //------------------------------------------------------------------------
          // Delete record
          //------------------------------------------------------------------------
          dcl-proc Delete_Record;

           Chain (DETAIL_NUM:DETAIL_LIN) ORDER_DETR;
             If %found();
               Delete ORD_DETL1;
           Endif;

          end-proc;
          //------------------------------------------------------------------------
          // Add record
          //------------------------------------------------------------------------
          dcl-proc RecordAdd;
            Dsply 'Add Record';
          end-proc;

          //-----------------------------------------------------------------
          // Validation Logic
          //-----------------------------------------------------------------
          dcl-proc ValidateRecord;
             Eval Error = *off;
             Eval ErrorMsg = *blanks;
             If (%Subst(S_SKU:1:1) < 'A') or
                      (%Subst(S_SKU:1:1) > 'Z');
               Eval ERRORMSG = 'SKU must start with alpha character';
               Eval Error = *on;
             ElseIf  (%len(%trim(S_SKU)) < 5) ;
               Eval ErrorMsg = 'SKU must be at least 5 characters';
               Eval Error = *on;
             EndIf;

          end-proc;
          //------------------------------------------------------------------------
          // Update Record
          //------------------------------------------------------------------------
          dcl-proc UpdateRecord;
             If Error = *Off;
                IF ACTION = 'ADD_RECORD';
                   Eval DETAIL_SKU =S_SKU;
                Else;
                 Chain (DETAIL_NUM:DETAIL_LIN) ORDER_DETR;
                 If %found();
                   Eval DETAIL_SKU =S_SKU;
                   Update ORDER_DETR;
                 Endif;
                EndIf;
             EndIf;
          end-proc;
          //------------------------------------------------------------------------
          // Init activities
          //------------------------------------------------------------------------
          dcl-proc Init;
            Z1SCREEN = %trimr(PgmDs.PgmName) + '-1';
            Eval Z1POS1  = 0;
            Eval Z1POS2  = 0;
            Eval PrvPos1 = 0;
            Eval PrvPos2 = 0;
          end-proc;

DDS:
     A* Display file: SF_07D
     A                                      DSPSIZ(24 80 *DS3)
     A                                      REF(*LIBL/ORDER_DET)
     A                                      PRINT
     A                                      INDARA
     A                                      CA03(03 'F3=Exit')
     A                                      CA06(06 'F6=Add')
     A                                      CF12(12 'F12=RETURN')
     A*----
     A* SubFile Record
     A          R SFL01                     SFL
     A            Z1RRN          2S 0H
     A            Z1OPT          1A  B  6  3
     A            DETAIL_NUMR     Y  O  6  6REFFLD(DETAIL_NUM)
     A                                      EDTCDE(4)
     A            DETAIL_LINR     Y  O  6 17REFFLD(DETAIL_LIN)
     A            DETAIL_SKUR        O  6 29REFFLD(DETAIL_SKU)

     A*----
     A* Control Record
     A          R CTL01                     SFLCTL(SFL01)
     A                                      SFLSIZ(16)
     A                                      SFLPAG(16)
     A                                      OVERLAY
     A                                      PAGEDOWN(25)
     A                                      PAGEUP(26)
     A  30                                  SFLDSPCTL
     A  31                                  SFLDSP
     A  32                                  SFLEND(*MORE)
     A  33                                  SFLCLR
     A                                      CA05(05 'F5=Refresh')
     A                                  3  2'Position to'
     A            Z1POS1    R        B  3 15REFFLD(DETAIL_NUM)
     A                                      COLOR(BLU)
     A            Z1POS2    R        B  3 26REFFLD(DETAIL_LIN)
     A                                      COLOR(BLU)
     A                                  4  2'Actions: 1=View'
     A                                      COLOR(BLU)
     A                                  4 19'2=Edit  4=Delete'
     A                                      COLOR(BLU)
     A                                  5  7'Order No'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  5 29'SKU'
     A                                      DSPATR(UL)
     A                                      DSPATR(HI)
     A                                  5 22'Line'
     A                                      DSPATR(UL)
     A                                      COLOR(WHT)
     A*----
     A          R WINDOW02                  WINDOW(3 2 15 63)
     A                                      OVERLAY
     A            Z2SCREEN      12A  O  1  2COLOR(BLU)
     A                                  1 53SYSNAME
     A                                      COLOR(BLU)
     A  50                              1 23'View Record'
     A  51                              1 23'Edit Record'
     A  52                              1 23'Add Record'
     A                                  5  4'Order'
     A                                      COLOR(WHT)
     A                                  6  4'Line'
     A                                      COLOR(WHT)
     A                                  7  4'SKU'
     A                                      COLOR(WHT)
     A            DETAIL_NUMR        O  5 22REFFLD(DETAIL_NUM)
     A                                      EDTCDE(4)
     A            DETAIL_LINR        O  6 22REFFLD(DETAIL_LIN)
     A                                      EDTCDE(4)
     A            S_SKU     R        B  7 22REFFLD(DETAIL_SKU)
     A  50                                  DSPATR(PR)
     A N50                                  DSPATR(UL)
     A                                 09 22'SKU cannot be blanks and must cont-
     A                                      ain an'
     A                                 10 22'alpha character in first position.'
     A                                 13  3'F3=Edit'
     A                                 13 14'Enter=Update'
     A                                 13 30'F12=Return'
     A            ERRORMSG      40A  O 14  3
     A                                      COLOR(RED)
     A
     A
     A*----
     A          R HEADER01
     A                                      OVERLAY
     A            Z1SCREEN      12A  O  1  2COLOR(BLU)
     A                                  1 72SYSNAME
     A                                      COLOR(BLU)
     A                                  1 21'Order Detail Screen'
     A*----
     A          R FOOTER01
     A                                      OVERLAY
     A                                 23  3'F3=Exit  F6=Add'
     A*----
     A          R DUMMY
     A                                      ASSUME
     A                                  1  2' '


5. Example of program message subfile
Features:
  • shows usage of message subfile for showing errrors on data entry
Show/Hide code


        // Program: SF_08
        // shows usage of message subfile for showing errrors on data entry

        // Setup:
        // Create order detail table, indexes, then add some data.
        //
        //   CREATE TABLE MYLIB/ORDER_DET (
        //       DETAIL_NUM INT NOT NULL WITH DEFAULT,
        //       DETAIL_LIN INT NOT NULL WITH DEFAULT,
        //       DETAIL_SKU CHAR (25) NOT NULL WITH DEFAULT,
        //       DETAIL_QTY INT NOT NULL WITH DEFAULT,
        //       DETAIL_PRI DEC ( 10, 2) NOT NULL WITH DEFAULT
        //    )
        //    RCDFMT  ORDER_DETR
        //
        //  Index:
        //    CREATE INDEX MYLIB/ORD_DETL1
        //      ON ORDER_DET(DETAIL_NUM, DETAIL_LIN)

        //  Create message file:
        //  CRTMSGF MSGF(MYLIB/MY_MSGF) TEXT('my test message file')
        //
        //  Add messages:
        //  ADDMSGD MSGID(MSG0014) MSGF(MY_MSGF) MSG('SKU cannot be blanks')
        //     SECLVL('SKU mandatory. Cannot be blanks.')
        //
        //  ADDMSGD MSGID(MSG0099) MSGF(MY_MSGF) MSG('Generic Message')

        // inspired by
        // https://www.go4as400.com/chapterload.aspx?cid=149
        // https://www.ibm.com/support/pages/example-message-subfile-ile-rpg-iv-program

        ctl-opt option(*nodebugio:*srcstmt:*nounref)  dftactgrp(*no) ;

        dcl-F SF_08D workstn indds(Indds);
        dcl-f ORD_DETL1 disk keyed
                        usage(*input: *update: *output: *delete);

        dcl-S S_Msg     char(30);

        dcl-pr SFMSGSFLCL extpgm('SFMSGSFLCL');
         MsgID          char(7);
         Msgf           char(10);
         MsgOpt         char(1);
        end-pr ;

        dcl-ds Indds qualified ;
           Exit      ind     pos(3)  ;
           Return12  ind     pos(12) ;
        end-ds ;

        dcl-s  MSGID    char(7);
        dcl-s  MSGF     char(10);
        dcl-s  MSGOPT   char(1);

        dcl-c true  const(*on);
        dcl-c false const(*off);

        //---------------------------------------------------------------------
        eval PgmQ ='SF_08';
        exsr GetNextRecord;
        exsr ProcessMsgSubfile;

        Dow ((Indds.Exit = false) and (Indds.Return12 = false));

          if ((Indds.Exit = true) or (Indds.Return12 = true));
            leave;
          endif;

          exsr ValidateUserInput;

          if S_MSG = *blanks;
            exsr UpdateRecord;
            exsr GetNextRecord;
            else;
              eval  S_MSG = 'MSG0099';
              exsr ShowMsg;
          endif;

         exsr ProcessMsgSubfile;
         exsr ClrMsgQ;
         eval S_MSG = *blanks;
       enddo;

       eval *InLR = *On;
       return;
       //---------------------------------------------------------------------
       begsr ProcessMsgSubfile;
        write Header02;
        write Footer02;
        write AccCtl;
        read Header02;
       endsr;
       //---------------------------------------------------------------------
       begsr ValidateUserInput;
         // SKU cannot be blanks else show message MSG0014
         if DI_SKU = *blanks;
           eval  S_MSG = 'MSG0014';
           exsr ShowMsg;
          eval  S_MSG = 'MSG0099';
           exsr ShowMsg;
          // eval  S_MSG = *blanks;
         endif;
       endsr;
       //---------------------------------------------------------------------
       Begsr UpdateRecord;
          Chain (DI_NUM:DI_LIN) ORDER_DETR;
          If %found();
             eval DETAIL_SKU = DI_SKU;
             update Order_DetR;
          Endif;
             eval DETAIL_SKU = DI_SKU;
             eval DETAIL_NUM = DI_NUM;
             eval DETAIL_LIN = DI_LIN;
             write Order_DetR;
             eval DI_SKU = *blanks;
       endsr;
        //---------------------------------------------------------------------
        Begsr SHOWMSG;
         EVAL  MSGID = S_MSG;
         EVAL  MSGF = 'MY_MSGF';
         EVAL  MSGOPT = 'I';
         Exsr Send;
       endsr;
        //---------------------------------------------------------------------
        Begsr Send;
           SFMSGSFLCL(MSGID:MSGF:MSGOPT);
        Endsr;
        //---------------------------------------------------------------------
        begsr CLRMSGQ;
         EVAL  MSGOPT = 'C';
         Exsr Send;
        endsr;
        //---------------------------------------------------------------------
        begsr GetNextRecord;
         setgt (*hival:*hival) ORDER_DETR;
         readp  ORDER_DETR;
         if not %Eof();
           DI_NUM = DETAIL_NUM ;
           DI_LIN = DETAIL_LIN + 1 ;
         else;
           Eval DETAIL_NUM = 1 ;
           Eval DETAIL_LIN = 1 ;
           DI_NUM = DETAIL_NUM ;
           DI_LIN = DETAIL_LIN;
         endif;
        Endsr;
DDS:
     A* Display File: SF_08D
     A                                      DSPSIZ(24 80 *DS3)
     A                                      REF(*LIBL/ORDER_DET)
     A                                      INDARA
     A                                      CA03(03 'EXIT')
     A                                      CA12(12 'PREVIOUS')
     A*-------------------------------
     A          R HEADER02
     A                                  1 30'Edit Order Detail'
     A                                      DSPATR(HI)
     A                                      COLOR(BLU)
     A                                  9  4'Order'
     A                                      COLOR(WHT)
     A                                 10  4'Line'
     A                                      COLOR(WHT)
     A                                 11  4'SKU'
     A                                      COLOR(WHT)
     A            DI_NUM    R        O  9 22REFFLD(DETAIL_NUM)
     A                                      EDTCDE(4)
     A            DI_LIN    R        O 10 22REFFLD(DETAIL_LIN)
     A                                      EDTCDE(4)
     A            DI_SKU    R        B 11 22REFFLD(DETAIL_SKU)
     A  50                                  DSPATR(PR)
     A N50                                  DSPATR(UL)
     A*-------------------------------
     A          R FOOTER02
     A                                      OVERLAY
     A                                 23  5'F3 = EXIT'
     A                                      DSPATR(HI)
     A                                      COLOR(BLU)
     A                                 23 20'F12 = CANCEL'
     A                                      DSPATR(HI)
     A                                      COLOR(BLU)
     A*-------------------------------
     A          R ACCSFL                    SFL
     A                                      SFLMSGRCD(24)
     A            MSGKEY                    SFLMSGKEY
     A            PGMQ                      SFLPGMQ(10)
     A*-------------------------------
     A          R ACCCTL                    SFLCTL(ACCSFL)
     A                                      OVERLAY
     A                                      SFLDSP
     A                                      SFLDSPCTL
     A                                      SFLINZ
     A N03                                  SFLEND(*PLUS)
     A                                      SFLSIZ(0002)
     A                                      SFLPAG(0001)
     A            PGMQ                      SFLPGMQ(10)
CL: SFMSGSFLCL
/* CL: SFMSGSFLCL      */
          PGM        PARM(&MSGID &MSGF &MSGOPT)
          DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)
          DCL        VAR(&MSGF) TYPE(*CHAR) LEN(10)
          DCL        VAR(&MSGOPT) TYPE(*CHAR) LEN(1)

          IF         COND(&MSGOPT *EQ 'I') THEN(SNDPGMMSG +
                        MSGID(&MSGID) MSGF(&MSGF))

          IF         COND(&MSGOPT *EQ 'C') THEN(RMVMSG PGMQ(*PRV +
                          (*)) CLEAR(*ALL))
          ENDPGM

IBM i Procedures and Service Programs


14. Example of old-school (pre-2001) program call
Show/Hide code

This program calls RPG_02 to add up two numbers using old-school (pre-2001) fixed-column coding for field definitions and calculations

      * Program Name: RPG_01
      * This program calls RPG_02 to add up two numbers
      *    using old-school (pre-2001) fixed-column coding
      *    for field definitions and calculations
      * Usage: Call RPG_01
     D
     D Var1            S              3P 0
     D Var2            S              3P 0
     D Response        S              4P 0

     C                   Eval      Var1 = 5
     C                   Eval      Var2 = 10

      * This is a fixed format RPG IV Call to external program RPG_02
      * to add up two numbers

     C                   Call      'RPG_02'
     C                   Parm                    Var1
     C                   Parm                    Var2
     C                   Parm                    Response

      * Display response
     C     Response      Dsply

     C                   Eval      *inlr = *on
     C                   Return




      // Program Name: RPG_02
      // This program receives two values, adds them together and return sum
      // in a third parameter called Response

     D Var1            S              3P 0
     D Var2            S              3P 0
     D Response        S              4P 0

     C     *Entry        PLIST
     C                   PARM                    Var1
     C                   PARM                    Var2
     C                   PARM                    Response

     C                   Eval      Response  =  var1 + var2

     C                   Eval      *inlr = *on
     C                   Return

15. Example of calling an RPGLE/free program using modern RPGLE and prototypes.
Show/Hide code

	   // Program Name: RPG_03
       // This program calls RPG_04 to add up two numbers
       // The CALLP operation is used to call prototyped program RPG_04

       // Takes advantage of improvements in RPG language over past few years including:
       //  1994 (IBM V3R1) - RPG IV (ILE RPG) Introduced (including CALLP)
       //  1999 (IBM V4R4) - Prototypes (Dcl-Pr) introduced
       //  2001 (V5R1) - Introduced free-form calculations - (/FREE and /END-FREE)
       //  2014 (IBM 7.1) - Allowed fully free-form RPG, including D-specs
       //        F-specs (file definitions), and P-specs (prototypes).
       //  2015 (IBM 7.2) - /FREE and /END-FREE became optional;
       //        all logic could be free-form by default.

       // Prototype for external program
       // Here the internal function name (Add_Two_Numbers) is clearer than RPG_04.

               Dcl-pr Add_Two_Number extpgm('RPG_04');
                 Var1     packed(3:0) ;
                 Var2     packed(3:0) ;
                 Response packed(4:0) ;
               End-pr ;

               Dcl-s Var1     packed(3:0) ;
               Dcl-s Var2     packed(3:0) ;
               Dcl-s Response packed(4:0) ;

        // Add two numbers
               Var1 = 5 ;
               Var2 = 10 ;

               // CALLP with prototype replaces CALL in RPG /free
				
               CALLP Add_Two_Number(Var1:Var2:Response);
               Dsply Response;
				
               Add_Two_Number(Var1:Var2:Response);
               Dsply Response;

               Eval  *inlr = *on;
               Return;       

RPGLE program RPG_04 is used to add up two values

Note use of prototype interface declaration (Dcl-pi) here for parameters

          // Program Name: RPG_04
          // This program receives two values, adds them together and returns them in third paramete

          // ctl-opt dftactgrp(*no) actgrp(*caller);

          Dcl-pi   RPG_04 extpgm('RPG_04');
            Var1      packed(3:0) ;
            Var2      packed(3:0) ;
            Response  packed(4:0) ;
          End-pi ;

          Eval  response  =  var1 + var2 ;

          Eval  *inlr = *on;
          Return;
          
16. Example of a sub-procedure defined and used within same program
Show/Hide code

The RPG subprocedure (Dcl-proc) is an alternative the RPG sub-routine (BEGSR).
  // Program  RPG_12
  // Example of a sub-procedure defined and used within same program
  // to compile: PDM-14 or CRTBNDRPG PGM(RPG_12) SRCMBR(RPG_12)

  // dftactgrp(*no) permits compiler to use the ILE sub-procedure functionality.     
  // compiler assumes we want actGrp(*caller) as we don't specify specific activation group

  Ctl-opt dftactgrp(*no) ;

  // This prototype is optional (but recommended) because procedure is not exported
  Dcl-pr  AddTwoNumbers  packed(4:0) ;
     Var1     packed(3:0) ;
     Var2     packed(3:0) ;
  End-pr ;

  Dcl-s Var1     packed(3:0) INZ(5) ;
  Dcl-s Var2     packed(3:0) INZ(5) ;
  Dcl-s Response packed(4:0)        ;

  Response = AddTwoNumbers(Var1:Var2) ;
  Dsply Response;

  Eval *INLR = *on;
  Return;

  // ---------------------------------------------------------------------
  // Define the subprocedure AddTwoNumbers
  // ---------------------------------------------------------------------
  // Procedure is only used in this program as it is not exported
  // note the return value is packed (4:0)
  
  Dcl-proc AddTwoNumbers ;

    Dcl-pi  AddTwoNumbers  packed(4:0) ;
      Var1     packed(3:0)             ;
      Var2     packed(3:0)             ;
    End-pi                             ;
      Dcl-s Reponse    packed(4:0)     ;

    Eval  Response  =  Var1 + Var2     ;
    Return Response                    ;

  End-Proc AddTwoNumbers ;
17. Example of sub-procedure and use of service program
Show/Hide code

Calling program:

  // Program RPG_21: Example of program calling module in service program that adds two numbers
  // to compile:
  // CHGCURLIB MYLIB
  // Create Module:
  // CRTRPGMOD MODULE(RPG_21) SRCFILE(QRPGLESRC) SRCMBR(RPG_21) DBGVIEW(*LIST)
  // to run: CALL RPG_21    

  ctl-opt option(*srcstmt:*nodebugio);

  Dcl-pr  AddTwoNumbers  packed(3:0) ;
     Var1     packed(3:0) ;
     Var2     packed(3:0) ;
  End-pr ;

  Dcl-s Var1     packed(3:0) ;
  Dcl-s Var2     packed(3:0) ;
  Dcl-s Response packed(3:0) ;

  Eval  Var1 = 5;
  Eval  Var2 = 5;

  Response = AddTwoNumbers(Var1:Var2) ;
  dsply Response;

  Eval *INLR = *on;
  Return;

Program containing subprocedure:

  // Program RPG_22: Example of sub-procedure that adds up two numbers compiled into service program
  // to Compile:
  // 1. Create Modules:
  //    CHGCURLIB MYLIB
  //    CRTRPGMOD MODULE(RPG_21) SRCFILE(QRPGLESRC) SRCMBR(RPG_21)
  //    CRTRPGMOD MODULE(RPG_22) SRCFILE(QRPGLESRC) SRCMBR(RPG_22)
  // 2. Create Service program:
  //    CRTSRVPGM SRVPGM(RPG_22) MODULE(RPG_22) EXPORT(*ALL)
  // 3. Create Program that includes calling module and service program
  //    CRTPGM PGM(RPG_21) MODULE(RPG_21)  BNDSRVPGM((RPG_22))

     Ctl-opt option(*srcstmt:*nodebugio) nomain ;

     Dcl-pr  AddTwoNumbers   packed(3:0) ;
       Var1      packed(3:0) ;
       Var2      packed(3:0) ;
     End-pr ;

    // ---------------------------------------------------------------

     Dcl-proc AddTwoNumbers export ;

       Dcl-pi AddTwoNumbers  packed(3:0);
         Var1      packed(3:0) ;
         Var2      packed(3:0) ;
       End-pi ;

       Dcl-s Response  packed(3:0) ;

       Eval Response = Var1 + Var2 ;

       Return Response ;

     End-proc AddTwoNumbers;
  
18. Same as above with external prototypes, binder language source and binding directory
Show/Hide code

Next we make a few changes to take advantage of more of IBM i's ILE features.

  1. Move prototypes to copy book mylib/QCPYSRC(RPG_21C) and re-create modules RPG_22
  2. Create and populate a binder language source file member
  3. Create a binding directory
  4. Create service program using specific binding instructions
  5. Add service program to binding directory
  6. Make sure your program refers to binding directory MYBNDDIR
  7. Create and run program RPG_21 using CRTPGM

Changes from previous example:

1. Move prototypes to copy book mylib/QCPYSRC(RPG_21C) and re-create modules RPG_22

Move prototypes to copy book to externalize the prototypes so they can be used in other modules. Create the following source file member in mylib/QCPYSRC(RPG_21C) and add the following code

  // Copy book RPG_21C        
  // Universal Prototype Definition             

    Dcl-pr  AddTwoNumbers  packed(3:0) ;        
      Var1     packed(3:0) ;                   
      Var2     packed(3:0) ;                   
    End-pr ;                                        

In RPGLE programs RPG_21 and RPG_22, replace prototypes with reference to copy file

// bring in prototypes from copy book in QCPYSRC     
  /copy qcpysrc,RPG_21C ;     

2. Create and populate a binder language source file member.

We want to avoid using CRTSRVPGM with EXPORT(*ALL). Instead, we will use a binder language source file to indicate exportable procedures.


Create a source file member QSRVSRC(RPG_22B) with source type "BND" with the following text:

/* ================================================== */      
/* source file: mylib/QSRVSRC(RPG_22B)                 */      
/* source type: BND                                   */      
/* New exports MUST be added at the end.              */      
/* Old exports MUST NEVER be removed from the list.   */      
/* !!! The order should not change                    */      
/* !!! The signature should not change                */      
/* ================================================== */      
STRPGMEXP  PGMLVL(*CURRENT) LVLCHK(*YES)                      
SIGNATURE('YourAppNameOrWhatever')                            
EXPORT SYMBOL(ADDTWONUMBERS)                                  
ENDPGMEXP                                                     

3. Create a binding directory

Create a binding directory if you don't already have one. This is an object of type *BNDDIR.

You may want to use a single binding directory for each service program, or combine multiple service programs in one binding directory. Here we call binding directory MYBNDDIR

CRTBNDDIR mylib/MYBNDDIR TEXT('My Binding Directory') 		  

4. Create service program using specific binding instructions

Create service program using specific binding instructions.

Here, instead of exporting *ALL procedures, we specify those indicated in our binder language source file member RPG_22B.

CRTSRVPGM SRVPGM(RPG_22) MODULE(RPG_22) EXPORT(*SRCFILE) SRCFILE(*LIBL/QSRVSRC) SRCMBR(RPG_22B) TEXT('Service Program RPG_22') 
5. Add service program to binding directory

ADDBNDDIRE BNDDIR(*LIBL/MYBNDDIR) OBJ((*LIBL/RPG_22 *SRVPGM))

Check contents of dinding directory.

DSPBNDDIR BNDDIR(MYBNDDIR) 

6. Make sure your program refers to binding directory MYBNDDIR

Add this line to your program RPG_21 this way when you compile RPG_21, compiler with check binding directory MYBNDDIR.

ctl-opt bnddir('*LIBL/MYBNDDIR') ;         
7. Create and run program RPG_21 using CRTPGM

	CRTPGM PGM(RPG_21) MODULE(RPG_21) 
  CALL RPG_21

Changes to programs in green:

  // Program RPG_21: Example of program calling module in service program that adds two numbers
  
  ctl-opt option(*srcstmt:*nodebugio);
  
  ctl-opt bnddir('*LIBL/MYBNDDIR') ;    

  // bring in prototypes from copy book in QCPYSRC     
  /copy qcpysrc,RPG_21C ;                                  
  
  Dcl-s Var1     packed(3:0) ;
  Dcl-s Var2     packed(3:0) ;
  Dcl-s Response packed(3:0) ;

  Eval  Var1 = 5;
  Eval  Var2 = 5;

  Response = AddTwoNumbers(Var1:Var2) ;
  dsply Response;

  Eval *INLR = *on;
  Return;

Program containing subprocedure:

  // Program RPG_22: Example of sub-procedure that adds up two numbers compiled into service program
  
     Ctl-opt option(*srcstmt:*nodebugio) nomain ;
     
     ctl-opt bnddir('*LIBL/MYBNDDIR') ;    

      // bring in prototypes from copy book in QCPYSRC     
      /copy qcpysrc,RPG_21C ;                                  
  
    // ---------------------------------------------------------------

     Dcl-proc AddTwoNumbers export ;

       Dcl-pi AddTwoNumbers  packed(3:0);
         Var1      packed(3:0) ;
         Var2      packed(3:0) ;
       End-pi ;

       Dcl-s Response  packed(3:0) ;

       Eval Response = Var1 + Var2 ;

       Return Response ;

     End-proc AddTwoNumbers;
  

Externalize the prototypes to copybook:


    // Copy book RPG_21C        
    // Universal Prototype Definition             

      Dcl-pr  AddTwoNumbers  packed(3:0) ;        
        Var1     packed(3:0) ;                   
        Var2     packed(3:0) ;                   
      End-pr ;                                    

SQL Functions and Procedures

19. Creating SQL Functions and Procedures that call RPG Service Programs
Show/Hide code

RPG Service Program:

          
         // Program RPG_23: Two examples of sub-procedures that adds up two numbers
         // to Compile:
         // 1. Create Modules:
         //    CHGCURLIB MYLIB
         //    CRTRPGMOD MODULE(RPG_23) SRCFILE(PROCEDURES) SRCMBR(UTIL)
         // 2. Create Service program:
         //    CRTSRVPGM SRVPGM(RPG_23) MODULE(UTIL) EXPORT(*ALL)

            Ctl-opt option(*srcstmt:*nodebugio) nomain ;

           // ---------------------------------------------------------------

           // Example of function:
           // this function returns sum of two packed numbers in a third parameter

              Dcl-proc SUMVALUES1 export;    // max 10 characters, can be lower/mixed case, but easier as uppercase

              Dcl-pi *n packed(15:5);
                a packed(15:5) const ;
                b packed(15:5) const ;
              End-pi ;

              Dcl-s c packed(15:5);

              c = a + b;

            snd-msg %char(c);

            return c;

            End-proc;
           // ---------------------------------------------------------------

           // Example of procedure:
           // this procedure returns sum of two packed numbers in a third parameter

              Dcl-proc SUMVALUES2 export;        // max 10 characters

              Dcl-pi *n ;
                a packed(15:5) const ;
                b packed(15:5) const ;
                c packed(15:5) ;
              End-pi ;

            c = a + b;

            End-proc;

2. Create RPG Module:

    CHGCURLIB MYLIB                                                         
    CRTRPGMOD MODULE(RPG_23) SRCFILE(PROCEDURES) SRCMBR(RPG_23)             

3. Create an RPG Service Program:

CRTSRVPGM SRVPGM(RPG_23) MODULE(RPG_23) EXPORT(*ALL)                   

4. Create an SQL Function

Use the IBM i Access Client Solutions "Run SQL Scripts tool". STRSQL does not seem to support the required syntax)

We may want to drop previously Created function first.

	
Drop function MYLIB.SUMVALUES1;

Create SQL function

	Create or replace function MYLIB.SUMVALUES1
	   (a decimal(15,5),
		b decimal(15,5) )
		returns decimal(15,5)
		
	external name 'MYLIB/RPG_23(SUMVALUES1)'
	language rpgle
	deterministic
	parameter style general;

5. call the Function

	SELECT MYLIB.SUMVALUES1( 21.1 , 51.1 )  from sysibm.sysdummy1;

6. Creating an SQL Procedure:

	Drop procedure MYLIB.SUMVALUES2;
	
	create or replace procedure MYLIB.SUMVALUES2
	   (in  var1 decimal(15,5),
		in  var2 decimal(15,5),
		out sum decimal(15,5) )
	external name 'MYLIB/RPG_23(SUMVALUES2)'
	language rpgle
	deterministic
	parameter style general;

7. Running an SQL Procedure:

	Create or replace variable MYLIB.sum dec(15,5);
	set MYLIB.sum = 0;
	call MYLIB.SUMVALUES2(1, 5, MYLIB.sum);                
	values MYLIB.sum;

8. List of procedures and functions

	SELECT substr(SPECIFIC_SCHEMA, 1, 20)as SPECIFIC_SCHEMA, 
	substr(SPECIFIC_NAME, 1, 20) as SPECIFIC_NAME, 
	substr(ROUTINE_SCHEMA, 1, 20) as ROUTINE_SCHEMA, 
	substr(ROUTINE_NAME, 1, 20) as ROUTINE_NAME,
	substr(EXTERNAL_NAME, 1, 30),  substr(ROUTINE_TYPE, 1, 20)
	EXTERNAL_LANGUAGE, PARAMETER_STYLE, IS_DETERMINISTIC
	FROM QSYS2.SYSROUTINES WHERE SPECIFIC_SCHEMA like '%MYLIB%'