• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • RPG Looks into the Future

    February 15, 2006 Ted Holt

    If you could write a program that could accurately predict the future, you’d be set for life. Unfortunately–or fortunately, depending on your point of view–such a program is not possible. But you can make a program look ahead as it reads a sequential data set, and that can be a valuable asset.

    The RPG cycle includes a handy lookahead feature, which allows a program to view data in the next record to be read, but it’s not available for externally described files, nor for full-procedural files. However, rolling your own lookahead logic is easy. To demonstrate just how easy it is, let’s consider a typical read-a-record, write-a-record program that generates a large report.

    H dftactgrp(*no) actgrp(*new)                         
                                                          
    Fqcustcdt  if   e             disk                    
    Fqsysprt   o    f  132        printer                 
                                                          
    D Save            ds                  likerec(CusRec) 
    D CurrentRec      ds                  likerec(CusRec) 
                                                          
    D eof             s               n                   
                                                          
    D LineOut         s            132a                   
                                                          
     /free                                                
         *inlr = *on;                                     
         exsr read;                                       
         dow not eof;                                     
            exsr PrintOneState;                           
         enddo;
    // ================================================== 
      begsr PrintOneState;                               
         Save.State = CurrentRec.State;                  
         dow not eof                                     
         and CurrentRec.State = Save.State;              
            LineOut = CurrentRec.STATE  + ' ' +          
                      %editc(CurrentRec.CUSNUM:'X') + ' ' + 
                      CurrentRec.LSTNAM + ' ' +            
                      CurrentRec.INIT   + ' ' +            
                      CurrentRec.STREET + ' ' +            
                      CurrentRec.CITY   + ' ' +            
                      %editc(CurrentRec.ZIPCOD:'X') + ' '; 
            except pline;                                  
            exsr read;                                     
         enddo;                                            
         except spacer;
    endsr;                                                 
    // ==================================================
    begsr read;                                          
         read CusRec CurrentRec;                           
         eof = %eof();                                     
      endsr;                                               
     /end-free                                             
                                                           
    Oqsysprt   e            pline       1                  
    O                       LineOut                        
    Oqsysprt   e            spacer
    O                                         '====='
    

    Notice the control break on state code. The report, run over a small dataset, looks like this:

    CA 475938 Doe      J W 59 Archer Rd  Sutter 95685
    =====                                            
    CO 389572 Stevens  K L 208 Snow Pass Denver 80226
    =====                                            
    GA 938485 Johnson  J A 3 Alpine Way  Helen  30545
    =====                                            
    MN 583990 Abraham  M T 392 Mill St   Isle   56342
    MN 846283 Alison   J S 787 Lake Dr   Isle   56342
    =====                                            
    NY 192837 Lee      F L 5963 Oak St   Hector 14841
    NY 839283 Jones    B D 21B NW 135 St Clay   13041
    NY 397267 Tyron    W E 13 Myrtle Dr  Hector 14841
    =====                                            
    TX 938472 Henning  G K 4859 Elm Ave  Dallas 75217
    TX 593029 Williams E D 485 SE 2 Ave  Dallas 75218
    =====                                            
    VT 392859 Vine     S S PO Box 79     Broton 05046
    =====                                            
    WY 693829 Thomas   A N 3 Dove Circle Casper 82609
    =====
    

    Suppose the people who get this report ask you for a “small” modification. (Does that sound familiar?) They’d like to be able to run the report as it is now, showing all records, but they’d also like to be able to run a summary report, which would take a lot less paper. By summary mode, they mean they only want to see the first record of each state and the separator line would not be needed. Piece of cake, right? But then they ask for one more thing. They’d also like to print a plus sign by the first record for a state if at least one other record for that state exists but is not printed, like this:

    CA 475938 Doe      J W 59 Archer Rd  Sutter 95685   
    CO 389572 Stevens  K L 208 Snow Pass Denver 80226   
    GA 938485 Johnson  J A 3 Alpine Way  Helen  30545   
    MN 583990 Abraham  M T 392 Mill St   Isle   56342 + 
    NY 192837 Lee      F L 5963 Oak St   Hector 14841 + 
    TX 938472 Henning  G K 4859 Elm Ave  Dallas 75217 + 
    VT 392859 Vine     S S PO Box 79     Broton 05046   
    WY 693829 Thomas   A N 3 Dove Circle Casper 82609
    

    There are probably several messy ways to handle this requirement, but determining whether more records of a group follow the first one would be easy if the program could see into the next record. Well, the program can. The trick is to read one record ahead, or to put it another way, to process not the last record read, but the next-to-last record. Look at the modified source code.

    H dftactgrp(*no) actgrp(*new)                           
                                                            
    Fqcustcdt  if   e             disk                      
    Fqsysprt   o    f  132        printer                   
                                                            
    D QAD465R         pr                  extpgm('QAD465R') 
    D  inSummary                      n   const             
    D QAD465R         pi                                    
    D  inSummary                      n   const             
                                                            
    D Save            ds                  likerec(CusRec)   
    D CurrentRec      ds                  likerec(CusRec)   
    D NextRec         ds                  likerec(CusRec)   
                                                            
    D eof             s               n                     
    D FirstRead       s               n   inz(*on)          
    D FirstOfState    s               n   inz(*on)          
    D NoNext          s               n                     
    
    D Mark            s              1a                    
    D LineOut         s            132a                    
                                                           
     /free                                                 
         *inlr = *on;                                      
         exsr read;                                        
         dow not eof;                                      
            exsr PrintOneState;                            
         enddo;                                            
      // ==================================================
      begsr PrintOneState;                                 
         Save.State = CurrentRec.State;                    
         FirstOfState = *on;                               
         dow not eof                                       
         and CurrentRec.State = Save.State;                
            if inSummary                                   
            and CurrentRec.State = NextRec.State;          
               Mark = '+';                                 
            else;                                          
               Mark = ' ';                                 
            endif;                                         
            if not inSummary                               
            or FirstOfState;                               
               LineOut = CurrentRec.STATE  + ' ' +         
                         %editc(CurrentRec.CUSNUM:'X') + ' ' +
                         CurrentRec.LSTNAM + ' ' +         
                         CurrentRec.INIT   + ' ' +         
                         CurrentRec.STREET + ' ' +         
                         CurrentRec.CITY   + ' ' +         
                         %editc(CurrentRec.ZIPCOD:'X') + ' ' +
                         Mark;                             
               except pline;                               
            endif;                                         
            FirstOfState = *off;                           
            exsr read;                                     
         enddo;                                            
         if not inSummary;                                 
            except spacer;                                 
         endif;                                            
      endsr;                                               
      // ==================================================
      begsr read;                                          
         if FirstRead;                                     
            exsr FetchNext;                                
            CurrentRec = NextRec;                          
            FirstRead = *off;                              
         endif;                                            
         if NoNext;                                        
            eof = *on;                                     
            leavesr;                                       
         endif;                                            
         CurrentRec = NextRec;                             
         exsr FetchNext;
      endsr;                                               
      // ==================================================
      begsr FetchNext;                                     
         read CusRec NextRec;                              
         NoNext = %eof();                                  
         if NoNext;                                        
            NextRec.State = *hival;                        
         endif;                                            
      endsr;                                               
     /end-free                                             
                                                           
    Oqsysprt   e            pline       1                  
    O                       LineOut                        
    Oqsysprt   e            spacer      1                  
    O                                              '====='
    

    The basic logic of the program is unchanged. The biggest difference is in the READ subroutine. READ’s mission is unchanged–it loads the next record to be processed into data structure CurrentRec. But the implementation has been changed so that it also loads the next record into the NextRec data structure. Looking ahead is a simple matter of accessing the NextRec data structure.

    The first time READ runs, it must fetch two records. The first one goes into the CurrentRec data structure and the second one goes into the NextRec data structure. Each time READ is called thereafter, it copies NextRec into CurrentRec and reads the next record into NextRec.

    Since READ has to read two records on the first pass, I split the subroutine into two subroutines. Subroutine READ loads the current record, and subroutine READNEXT loads the next record. Notice that I move a dummy high value into state so that the lookahead logic isn’t fooled into thinking that another record exists with the same state value as the last record.

    I’d also like to point out that the CurrentRec and NextRec data structures are defined using the LIKEREC keyword. Any data structure that is defined with LIKEREC is automatically qualified. That is, its subfields can have the same names as subfields or variables used elsewhere in the procedure. To reference the subfields of a qualified data structure, use the dot notation–data structure name, dot, subfield name. In both versions of the program, I also defined the Save data structure with LIKEDS, which gave me a handy way to properly define save fields for control breaks.

    To make this program print either the full report or a summary report, I added a parameter, inSummary. It is used to control the printing of the plus sign, the printing of the second and following details lines of a control group, and the separator line.

    By the way, if you want to play with this technique and want to use the sample dataset, run the following commands on your system. First, run this Create Duplicate Object command from a CL command line, replacing xxx with the name of your library.

    CRTDUPOBJ OBJ(QCUSTCDT) FROMLIB(QIWS) OBJTYPE(*FILE)  
              TOLIB(xxx) DATA(*NO)       
    

    Then run this SQL command through Interactive SQL, iSeries Navigator, or some other SQL interface, to load the sorted data into the file you just created.

    insert into xxx/qcustcdt   
      select * from qiws/qcustcdt
      order by state, baldue desc
    

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    DRV Tech

    Get More Out of Your IBM i

    With soaring costs, operational data is more critical than ever. IBM shops need faster, easier ways to distribute IBM applications-based data to users more efficiently, no matter where they are.

    The Problem:

    For Users, IBM Data Can Be Difficult to Get To

    IBM Applications generate reports as spooled files, originally designed to be printed. Often those reports are packed together with so much data it makes them difficult to read. Add to that hardcopy is a pain to distribute. User-friendly formats like Excel and PDF are better, offering sorting, searching, and easy portability but getting IBM reports into these formats can be tricky without the right tools.

    The Solution:

    IBM i Reports can easily be converted to easy to read and share formats like Excel and PDF and Delivered by Email

    Converting IBM i, iSeries, and AS400 reports into Excel and PDF is now a lot easier with SpoolFlex software by DRV Tech.  If you or your users are still doing this manually, think how much time is wasted dragging and reformatting to make a report readable. How much time would be saved if they were automatically formatted correctly and delivered to one or multiple recipients.

    SpoolFlex converts spooled files to Excel and PDF, automatically emailing them, and saving copies to network shared folders. SpoolFlex converts complex reports to Excel, removing unwanted headers, splitting large reports out for individual recipients, and delivering to users whether they are at the office or working from home.

    Watch our 2-minute video and see DRV’s powerful SpoolFlex software can solve your file conversion challenges.

    Watch Video

    DRV Tech

    www.drvtech.com

    866.378.3366

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Sponsored Links

    COMMON:  Join us at the Spring 2006 conference, March 26-30, in Minneapolis, Minnesota
    T.L. Ashford:  BARCODE400 - the fastest way to create compliance labels directly from the iSeries
    California Software:  Migrate iSeries apps to Windows, Linux, or Unix

    Enterprise Application Mergers and Acquisitions Big and Getting Bigger Service with a Smile–and a Wink and a Nod

    Leave a Reply Cancel reply

Volume 6, Number 7 -- February 15, 2006
THIS ISSUE SPONSORED BY:

ProData Computer Svcs
iTera
Asymex

Table of Contents

  • RPG Looks into the Future
  • Work Fields and SQL
  • When Users Need to Create Duplicate Objects

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • Meet The Next Gen Of IBMers Helping To Build IBM i
  • Looks Like IBM Is Building A Linux-Like PASE For IBM i After All
  • Will Independent IBM i Clouds Survive PowerVS?
  • Now, IBM Is Jacking Up Hardware Maintenance Prices
  • IBM i PTF Guide, Volume 27, Number 24
  • Big Blue Raises IBM i License Transfer Fees, Other Prices
  • Keep The IBM i Youth Movement Going With More Training, Better Tools
  • Remain Begins Migrating DevOps Tools To VS Code
  • IBM Readies LTO-10 Tape Drives And Libraries
  • IBM i PTF Guide, Volume 27, Number 23

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2025 IT Jungle