RPG Free Format: Single Page Subfile SQLRPGLE Example Program *






 


#IBMiSample

The standard subfile has a limit of 9999 lines and works wery well.

But in case of heavy processing, loading the entire file can take a long time. So, in some cases is better to load one page at a time.

I received several comments to this statement, so I thought I'd clarify my opinion with two examples.


Scenario 1 small file:

The subfilesize is 20.

You have to process a file of 5000 records, so you may think this is a ideal scenario for a standard subfile processing, bat you want to filter only specific records, for example records with a flag=’X’ and creation date between two specific dates. The total number of this records is, for example, 280 so you get the first page after processing the entire file.

With a single page process, you get the first page after finding the first 20 records that match your filters. Faster then standard subfile processing.

Scenario 2 big file

The subfilesize is 20.

You have to process a file of 50 million records, bat obviously you want to filter only specific records, for example records with a flag=’X’ and creation date between two specific dates. The total number of this records is, for example 280, so you get the first page after processing the first 9999 records that match your filters (You scanned 50 million records before an answer!).

With a single page process, you get the first page after finding the first 20 records records that match your filters, and you are able to process the file to the end. Faster then standard subfile processing.

So, in some cases is better to load one page at a time.

That's how.

First of all look at this post and compile and populate these files to use this example.


Then copy e compile the following sources. 

Display file:
OT04SFV.DSPF
      * Description... Template Single Page Subfile SQLRPGLE Program
      * File Name..... OT04SF.DSPF
      * Author........ Aldo SUCCI from  idea of Nick Litten
      *                (https://www.nicklitten.com)
      * https://www.nicklitten.com/example-of-an-ibm-i-rpg-single-page-subfile
      * Date.......... Jan 21th 2019
      * Compile Instructions:
      * CRTDSPF FILE(YourLib/OT04SFV) SRCFILE(YourLib/OT04) SRCMBR(OT04SFV)
      *
     A                                      DSPSIZ(27 132 *DS4)
     A                                      REF(*LIBL/OTORD00F)
     A                                      PRINT
     A                                      INDARA
     A                                      ERRSFL
     A                                      HELP(01)
     A                                      CA03(03)
     A                                      CA05(05)
     A                                      CA12(12)
     A                                      PAGEUP(25)
     A                                      PAGEDOWN(26)
     A          R SFL01                     SFL
     A            SFLRRN         5S 0H
     A            S1OPT          1A  B  5  2
     A            OTCOR0    R        O   + 1EDTCDE(4)
     A            OTDTA0    R        O   + 1EDTWRD('  /  /  ')
     A            OTDTP0    R        O   + 1EDTWRD('  /  /  ')
     A            OTCCM0    R        O   + 1
     A            OTTIP0    R        O   + 1
     A            CLNOM0    R        O   + 1REFFLD(CLANA/CLNOM0 CLANA00F)
     A          R CTL01                     SFLCTL(SFL01)
     A                                      SFLSIZ(0019)
     A                                      SFLPAG(0019)
     A                                      OVERLAY
     A  30                                  SFLDSP
     A  31                                  SFLDSPCTL
     A  32                                  SFLCLR
     A                                  1  3'Template Single Page Subfile SQLRP-
     A                                      GLE Program'
     A                                      COLOR(WHT)
     A                                  3 12'__Chk_in'
     A                                   + 1'__ChkOut'
     A                                   + 1'RoomNb'
     A                                   + 1'Tr'
     A                                   + 1'Name'
     A          R CMD01
     A                                      OVERLAY
     A                                 25  3'F3=Exit  F5=Refresh'
     A            ERRORMSG     120A  O 26  2COLOR(RED)

RPG Free Program:
OT04SF.SQLRPGLE

      **FREE
       // Description... Template Single Page Subfile SQLRPGLE Program
       // File Name..... OT04SF.SQLRPGLE
       // Author........ Aldo SUCCI from  idea of Nick Litten
       //                (https://www.nicklitten.com)
       // https://www.nicklitten.com/example-of-an-ibm-i-rpg-single-page-subfile
       // Date.......... Jan 21th 2019
       //
       // Compile Instructions:
       // CRTSQLRPGI OBJ(YourLib/OT04SF) SRCFILE(YourLib/QRPGLESRC) SRCMBR(OT04SF)
       // OBJTYPE(*PGM)                                                                   //
       // Run instruction:
       // call OT04SF
       ctl-opt
        debug
        option(*nodebugio:*srcstmt)
        datfmt(*iso-) timfmt(*iso.)
        indent('| ') truncnbr(*yes) expropts(*resdecpos)
        copyright('| TEMPLATE Single Page Subfile SQLRPGLE Program')
        dftactgrp(*NO)
       ;
       dcl-f CLANA01L keyed usage (*input); // Customer File
       dcl-f OT04SFV workstn sfile(SFL01:rrn)  indDs(dspf); // Displayfile
       dcl-s p_Indicators pointer inz(%addr(*in));
       dcl-ds dspf qualified based(p_Indicators);
         help     ind pos(01);
         exit     ind pos(03);
         refresh  ind pos(05);
         previous ind pos(12);
         pageup   ind pos(25);
         pagedown ind pos(26);
         sflclr   ind pos(32);
         sfldsp   ind pos(30);
         sflctl   ind pos(31);
         sflEnd   ind pos(35);
       end-ds;
       dcl-s Position like(OTCOR0) ;
       dcl-s IndexPag like(OTCOR0) ;
       dcl-s PaginaST like(OTCOR0) dim(10000) ;
       dcl-s PaginaEN like(OTCOR0) dim(10000) ;
       dcl-s EndOfData char(1);
       dcl-ds dsp_fields extname('OTORD00F') end-ds;
       dcl-s rrn like(sflrrn);
       dcl-s pagesize zoned(2) inz(19);
       // *********************************************************************
       // PGM start
       // *********************************************************************
       exec sql
         set option commit = *none,
                               closqlcsr = *endmod;
       // initially let's force a refresh to load first page
       dspf.refresh = *on;
       dou dspf.exit or dspf.previous;
         if dspf.refresh;
           // Pointer of current page displayed
           IndexPag = 1;       // Page number
           PaginaST = 0;       // First record key of x Page
           PaginaEN = 9999999; // Last record key of x Page
           clearSubfile();
           setPage();
           loadSubfile();
         elseif dspf.pageUp;
           setPage();          // Return to the previous page
           pageUp();
         elseif dspf.pagedown;
           pageDown();         // Go to next page
         endif;
         showSubfile();        // show screen
       enddo;
       *inlr = '1';
       return;
       // *********************************************************************
       // Clear Subfile procedure...
       // *********************************************************************
       dcl-proc clearSubfile;
         dspf.sflEnd = *off;
         dspf.sflclr = *on;
         write ctl01;
         dspf.sflclr = *off;
       end-proc;
       // *********************************************************************
       // Build Subfile procedure...
       // *********************************************************************
       dcl-proc loadSubfile;
         dspf.sflEnd = *off;
         rrn = 0;
         exec sql
           fetch next from mycursor
             into :dsp_fields;
       // Start pointer of current page
         if sqlcode < 0 or sqlcode >= 100;
           OTCOR0 = 0;
         endif;
         PaginaST(IndexPag)= OTCOR0;
         dow sqlcode >= 0 and sqlcode < 100;
           GetCustomer(); // Get Customer name
           rrn += 1;
           write SFL01;
           if rrn = pagesize;
             leave;
           endif;
           // get next record
           exec sql
             fetch next from mycursor
               into :dsp_fields;
         enddo;
       // End pointer of current page
         PaginaEN(IndexPag)= OTCOR0; // Chiave x prossimo SETLL+1
         // if we didnt load a full page then set END OF SUBFILE
         if rrn < pagesize;
           dspf.sflEnd = *on;
         endif;
       end-proc;
       // *********************************************************************
       // Display Subfile procedure...
       // *********************************************************************
       dcl-proc showSubfile;
         if rrn < pagesize;
           errormsg = 'Start of data';
         endif;
         if rrn > 0;
           dspf.sfldsp = *on;
         else;
           dspf.sfldsp = *off;
           errormsg = 'No more data from OTORD00F!';
         endif;
         dspf.sflctl = *on;
         write cmd01;
         exfmt ctl01;
         clear ERRORMSG;
       end-proc;
       // *********************************************************************
       // Get Customer...
       // *********************************************************************
       dcl-proc GetCustomer;
         chain (OTCCL0) CLANA;
         if %found(CLANA01L);
         else;
           clear CLNOM0;
         endif;
       end-proc;

       // *********************************************************************
       // Declare cursor procedure...
       // *********************************************************************
       dcl-proc setPage;
         position = 0;
         if (IndexPag>1);
           position = PaginaEN(IndexPag-1)+1;
           if (dspf.pageup);
             position = PaginaST(IndexPag-1);
           endif;
         endif;
         exec sql
           close mycursor;
         exec sql
           declare mycursor scroll cursor for
             select *
               from OTORD00F
               where OTCOR0 >= :position
               order by OTCOR0
               limit 19
               for read only;
         exec sql
           open mycursor;
       end-proc;
       // *********************************************************************
       // Page up procedure...
       // *********************************************************************
       dcl-proc pageUp;
         // set start cursor RRN at first row of previous page
           clear position;
           EndofData = ' ';
       //  if rrn = pagesize;
           if IndexPag > 1;
             IndexPag = IndexPag - 1;
           endif;
       //  else;
       //    clear position;
       //  endif;
         // Build the subfile starting at *position*
         clearSubfile();
         loadSubfile();
         // If the cursor already in the top the list
         if rrn <= pagesize;
       //    errormsg = 'Start of customer list';
         endif;
         if IndexPag <= 1;
           errormsg = 'Start of customer list';
         endif;
       end-proc;
       // *********************************************************************
       // Page down procedure...
       // *********************************************************************
       dcl-proc pageDown;
         if (EndOfData='Y');
         else;
           IndexPag = IndexPag + 1;
         endif;
         // Build the subfile starting at *position*
         clearSubfile();
         setpage();
         loadSubfile();
         // If more to read then show sflend
         EndofData = ' ';
         if rrn < pagesize;
           errormsg = 'You have reached the bottom of the customer list.';
           EndofData = 'Y';
         endif;
       end-proc;

Don't forget to set the screen to 132 columns!


I appreciate all the comments made on this blog.

Comments

  1. Great job, thanks for clearing this out!

    ReplyDelete
  2. Replies
    1. Hi Nick, I just wanted to say thank you so much for providing me with that RPG source code. It was really helpful in getting the example I needed. I appreciate your willingness to help out and share your expertise. Thanks again!

      Delete
  3. This is neat, but I find the need for single page subfiles extremely rare. In most cases, one page a time technique for multi-page subfiles will suffice, in my opinion.

    ReplyDelete
    Replies
    1. Thank you, Alex, for your comment!

      I completely understand your point. The single-page subfile technique might indeed seem less common compared to multi-page subfiles, especially in scenarios where users prefer to navigate through multiple pages of data.

      However, the single-page subfile offers a distinct advantage in situations where we need to display dynamic content that updates frequently or where the amount of data is relatively small and fits comfortably within one screen. This approach simplifies both programming and user interaction in such cases.

      That said, the choice between single-page and multi-page subfiles ultimately depends on the specific requirements of the application and user expectations. I appreciate your perspective—it’s always valuable to hear how others approach these challenges!

      What are your favorite use cases for multi-page subfiles? I’d love to hear more!

      Delete
    2. Sure thing. One particular scenario where a program controlled PageUp might be helpful is when user needs to seamlessly roll from "first" to "last" page.

      To answer your question, to be honest, I've been coding multi-page subfiles exclusively. But - to load one page at a time technique is my favorite by far. Just a tiny bit more effort will buy you a great deal of versatility, especially, when the size of the underlying database cannot be reliably assessed at programming time.

      Delete
    3. Exactly. I wanted to add that one important consideration when working with subfiles is the 9999-record limit. This restriction is inherent to the IBM i system, as the subfile record number is stored in a 4-digit field.

      While the one-page-at-a-time technique is my preferred approach for multi-page subfiles, it also helps to bypass this limitation effectively. It ensures that only the necessary records are loaded for the current page, making it ideal for handling large datasets without hitting the system’s constraints.

      Delete

Post a Comment

Popular posts from this blog

(IBM i fans only) Efficient WRKSPLF with WSF - How to Search string into spooled files, Sort, and Generate PDFs on IBMi

(IBM i fans only) Detecting and Handling Non-Printable Characters in DB2 SQL Using LOCATE() and REPLACE() Functions

(IBM i fans only) How to Sniff User Access