ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

Arrays as parameter in RPLGE

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Arrays as parameter in RPLGE

    Hi,

    Can an array of record can be passed as parameter in RPGLE? If yes please give me a sample example on how to use that.

    Regards
    Regu

  • #2
    Re: Arrays as parameter in RPLGE

    You could do an array datastructure and use the LikeDS keyword. To get a datastructure the same format as your file you can define a DS and use the extname keyword. You will need to add both the datastructure and prototype to a /copy member because the calling program would not compile with the prototype alone.

    e.g.
    PHP Code:
    D MyFileDS      E DS                  EXTNAME(MYFILE)      
    ...
    D myProcedure      PR     
    D  RecChgs                            LikeDS
    (MyFileDSDim(50
    Ben

    Comment


    • #3
      Re: Arrays as parameter in RPLGE

      Another method (which prevents a hard-coded number of array elements) is to place the array into a user space. Then two parameters can be passed to the called program; a pointer to the user space and the number of array elements the user space contains.
      Michael Catalani
      IS Director, eCommerce & Web Development
      Acceptance Insurance Corporation
      www.AcceptanceInsurance.com
      www.ProvatoSys.com

      Comment


      • #4
        Re: Arrays as parameter in RPLGE

        It might be better to think of a different way to do this. I don't know what your exact requirements are but neither of these solutions is ideal. What happens if the file/datastructure changes? How many times are you likely to call the procedure? (The user space one could be a bit fiddly if you call it a lot)
        Ben

        Comment


        • #5
          Re: Arrays as parameter in RPLGE

          Originally posted by BenThurley View Post
          What happens if the file/datastructure changes?
          Those changes are picked up automatically on a re-compile.

          I've used user spaces since they were introduced. They are not fiddly at all. In fact, if you call a routine a lot, this would be a very good method, because it limits the parameter bandwidth to that of a pointer and a (10i 0) field (which tells the receiving program how many entries there are), no matter how many elements the array has. Otherwise, you would have to pass a parameter the entire size of the array, no matter if the elements were all used or not.
          Michael Catalani
          IS Director, eCommerce & Web Development
          Acceptance Insurance Corporation
          www.AcceptanceInsurance.com
          www.ProvatoSys.com

          Comment


          • #6
            Re: Arrays as parameter in RPLGE

            Originally posted by MichaelCatalani View Post
            Those changes are picked up automatically on a re-compile.

            I've used user spaces since they were introduced. They are not fiddly at all. In fact, if you call a routine a lot, this would be a very good method, because it limits the parameter bandwidth to that of a pointer and a (10i 0) field (which tells the receiving program how many entries there are), no matter how many elements the array has. Otherwise, you would have to pass a parameter the entire size of the array, no matter if the elements were all used or not.
            hi michael,
            do you have an example source code to this? this is interest thing
            i want learn about it

            thx u

            Comment


            • #7
              Re: Arrays as parameter in RPLGE

              For all those people who find it more convenient to bother you with their question rather than to Google it for themselves.
              "Time passes, but sometimes it beats the <crap> out of you as it goes."

              Comment


              • #8
                Re: Arrays as parameter in RPLGE

                I have a quick example that I'll place in the next post. First, here's two source members you will need, as they are copy members used in the program.

                The first source member is the User Space prototypes, and the source member is called USERSPAC_P.

                Code:
                                                                                      
                                                                                
                   //* * * * * * * * * * * * * * * * * * * * * * * * * * * *    
                   //                                                           
                   //   User Space Prototypes                                   
                   //   ©copyright 1998 Michael Catalani                        
                   //                                                           
                   //                                                           
                   //   L i s t    O f   P r o t o t y p e s                    
                   //                                                           
                   //   Procedure                    Description                
                   //   UserSpace_Create             Prototype for QUSCRTUS     
                   //   UserSpace_Delete             Prototype for QUSDLTUS     
                   //   UserSpace_Retrieve           Prototype for QUSRTVUS     
                   //   UserSpace_Pointer...         Prototype for QUSPTRUS     
                   //   UserSpace_Change             Prototype for QUSCHGUS     
                   //   UserSpace_CreateUserSpace    Wrapper for QUSCRTUS Api   
                   //                                                           
                   //* * * * * * * * * * * * * * * * * * * * * * * * * * * *    
                                                                                
                 /if defined( UserSpace )                                             
                 /eof                                                                 
                 /endif                                                               
                                                                                      
                 /define UserSpace                                                    
                                                                                      
                 /copy *libl/qrpglesrc,ApiError                                       
                                                                                      
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *          
                 *                                                                    
                 *  UserSpace_Create - Calls the QUSCRTUS (create User Space API)     
                 *                     Creates a User Space                           
                 *                                                                    
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *          
                d UserSpace_Create...                                                 
                d                 pr                  ExtPgm( 'QUSCRTUS' )            
                d  UserSpace                    20a   Const                           
                d  ExternalAttribute...                                               
                d                               10a   Const                           
                d  InitialSize...                                                     
                d                               10i 0 Const                           
                d  InitialValue...                                                    
                d                                1a   Const                           
                d  PublicAuthority...                                                 
                d                               10a   Const                           
                d  Text                         50a   Const                           
                d  Replace                      10a   Const                           
                d  Error                              Like( ApiError )                
                                                                                      
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *          
                 *                                                                    
                 *  UserSpace_Delete - Calls the QUSDLTUS (delete User Space API)     
                 *                     Deletes a User Space                           
                 *                                                                    
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *          
                d UserSpace_Delete...                                                 
                d                 pr                  ExtPgm( 'QUSDLTUS' )            
                d  UserSpace                    20a   Const                           
                d  Error                              Like( ApiError )                
                                                                                      
                                                                                       
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *           
                 *                                                                     
                 *  UserSpace_Retrieve - Calls the QUSRTVUS (retrive User Space API)   
                 *                       Retrieves data from a User Space              
                 *                                                                     
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *           
                d UserSpace_Retrieve...                                                
                d                 pr                  ExtPgm( 'QUSRTVUS' )             
                d  UserSpace                    20a   Const                            
                d  StartPosition...                                                    
                d                               10i 0 Const                            
                d  LengthOfData...                                                     
                d                               10i 0 Const                            
                d  Receiver                1000000a   Options( *VarSize )              
                d  Error                              Like( ApiError )                 
                                                                                       
                                                                                       
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *           
                 *                                                                     
                 *  UserSpace_Pointer - Calls the QUSPTRUS (retrieve pointer api)   
                 *                      Retrieves the pointer for the user space    
                 *                                                                  
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *        
                d UserSpace_Pointer...                                              
                d                                                                   
                d                 pr                  ExtPgm( 'QUSPTRUS' )          
                d  UserSpace                    20a   Const                         
                d  Pointer                        *                                 
                                                                                    
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *        
                 *                                                                  
                 *  UserSpace_Change - Calls the QUSCHGUS (Change User Space API)   
                 *                       Writes / Changes data to a User Space      
                 *                                                                  
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *        
                d UserSpace_Change...                                               
                d                 pr                  ExtPgm( 'QUSCHGUS' )          
                d  UserSpace                    20a   Const                         
                d  StartPosition...                                                 
                d                               10i 0 Const                         
                d  LengthOfData...                                                  
                d                               10i 0 Const                         
                d  DataPTR                 1000000a   Const Options( *VarSize )     
                d  ForceToDasd                   1a   Const                         
                d  Error                              Like( ApiError )              
                                                                                    
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *        
                 *                                                                  
                 *  UserSpace_UserSpaceCreate - Creates a User Space                
                 *                                                                  
                 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *        
                d UserSpace_CreateUserSpace...                                      
                d                 pr                                                
                d   UserSpace                   20a   Const


                Last edited by MichaelCatalani; August 24, 2010, 08:44 PM.
                Michael Catalani
                IS Director, eCommerce & Web Development
                Acceptance Insurance Corporation
                www.AcceptanceInsurance.com
                www.ProvatoSys.com

                Comment


                • #9
                  Re: Arrays as parameter in RPLGE

                  Here's the second copy member. Its the error data structure used for the api's. Its in a member called APIERROR.

                  Code:
                   
                   /if defined(ApiError)                                              
                   /eof                                                               
                   /endif                                                             
                                                                                      
                   /define ApiError                                                   
                                                                                      
                  d ApiError        Ds                  Inz qualified                 
                  d  Bytes                        10i 0 Inz( %Size( ApiError ))       
                  d  BytesAvailable...                                                
                  d                               10i 0 Inz                           
                  d  ErrorID                       7a   Inz                           
                  d  Reserved                      1a   Inz( x'00' )                  
                  d  MessageData                 128a   Inz
                  Michael Catalani
                  IS Director, eCommerce & Web Development
                  Acceptance Insurance Corporation
                  www.AcceptanceInsurance.com
                  www.ProvatoSys.com

                  Comment


                  • #10
                    Re: Arrays as parameter in RPLGE

                    Here's the first program, called US1:

                    Code:
                    h DftActGrp( *No )  ActGrp( *New )                             
                                                                                   
                     /copy *libl/qrpglesrc,UserSpac_P                              
                                                                                   
                    d TotalEntries    s             10i 0 inz( 5 )                 
                    d Count           s             10i 0                          
                    d DataPTR         s               *                            
                                                                                   
                    d SpaceValue      s              1a   inz( *blanks )           
                    d SpaceAuthority  s             10a   inz( '*CHANGE' )         
                    d SpaceText       s             50a   inz( *blanks )           
                    d SpaceReplace    s             10a   inz( '*YES' )            
                    d SpaceAttribute  s             10a   inz( *blanks )           
                    d SpaceSize       s             10i 0 inz( 4096 )              
                                                                                   
                    d DataDS          ds                  Qualified                
                    d  EntryNumber                  10i 0                          
                    d  TimeStamp                      z                            
                                                                                   
                    d UserSpace       ds                                          
                    d  SpaceName                    10a   Inz( 'TEST' )           
                    d  SpaceLibrary                 10a   Inz( 'QTEMP' )          
                                                                                  
                    d CallProgram     pr                  ExtPgm( 'US2' )         
                    d   DataPTR                       *                           
                    d   TotalEntries                10i 0                         
                                                                                  
                     /free                                                        
                                                                                  
                      // *** Delete User Space If It Exists *** //                
                      reset ApiError;                                             
                      UserSpace_Delete( UserSpace : ApiError );                   
                                                                                  
                      // *** Create User Space *** //                             
                      reset ApiError;                                             
                      UserSpace_Create(  UserSpace                                
                                       : SpaceAttribute                           
                                       : SpaceSize                                
                                       : SpaceValue                               
                                       : SpaceAuthority                                 
                                       : SpaceText                                      
                                       : SpaceReplace                                   
                                       : ApiError                                       
                                         );                                             
                                                                                        
                       for Count = 1 to TotalEntries;                                   
                         DataDS.EntryNumber = Count;                                    
                         DataDS.TimeStamp = %timestamp;                                 
                                                                                        
                          // *** Add Data Structure Data To User Space *** //           
                          reset ApiError;                                               
                          UserSpace_Change(  UserSpace                                  
                                           : ( Count - 1 ) * %size( DataDS ) + 1        
                                           : %size( DataDS )                            
                                           : DataDS                                     
                                           : '0'                                        
                                           : ApiError                                   
                                             );                                         
                                                                                        
                        endfor;                                         
                                                                        
                        UserSpace_Pointer(  UserSpace                   
                                          : DataPTR                     
                                            );                          
                                                                        
                        CallProgram(  DataPTR                           
                                    : TotalEntries                      
                                      );                                
                                                                        
                        return;
                    Michael Catalani
                    IS Director, eCommerce & Web Development
                    Acceptance Insurance Corporation
                    www.AcceptanceInsurance.com
                    www.ProvatoSys.com

                    Comment


                    • #11
                      Re: Arrays as parameter in RPLGE

                      And here's the second program, called US2. I'm near brain dead, so there may be something I missed.

                      Code:
                       
                      h DftActGrp( *No )  ActGrp( *New )                                  
                                                                                          
                      d Count           s             10i 0                               
                                                                                          
                      d DataDS          ds                  Qualified                     
                      d                                     Based( DataPTR )              
                      d  EntryNumber                  10i 0                               
                      d  TimeStamp                      z                                 
                                                                                          
                      d Main            pr                  ExtPgm( 'US2' )               
                      d   DataPTR                       *                                 
                      d   TotalEntries                10i 0                               
                                                                                          
                      d Main            pi                                                
                      d   DataPTR                       *                                 
                      d   TotalEntries                10i 0                               
                                                                                          
                       /free                                                              
                          for Count = 1 to TotalEntries;      
                            dsply %char( DataDS.EntryNumber );         
                            dsply %char( DataDS.TimeStamp );           
                            DataPTR += %size( DataDS );                
                          endfor;                                      
                          return;
                      Michael Catalani
                      IS Director, eCommerce & Web Development
                      Acceptance Insurance Corporation
                      www.AcceptanceInsurance.com
                      www.ProvatoSys.com

                      Comment


                      • #12
                        Re: Arrays as parameter in RPLGE

                        The beauty of this type of setup is multi-fold; First, notice that there is no user space definitions or api's needed for the second program. We simply pass it a pointer to the start of the data of the user space, and it handles extracting the data without any user space api's.

                        Second, the parameter interface is always a pointer, and the number of entries. No matter if we have one entry, or one million. (A design concept to keep in mind is that we could pass a third parameter, which is the length of each entry. This is so that if we add additional fields to the end of the data structure in program 1, we dont need to recompile program 2 in order for it to continue to work. Instead of adding the %size( DataDS ) to the pointer to get to the next data entry, we would add the 3rd parameter value to the pointer. We can modify these two programs pretty quick to simulate this if you want to see what I mean.)

                        This setup is especially nice if you really dont need an array, but simply a way of grouping data into a list and passing it to another program. (Notice that there are no arrays in either program) This design keeps the program storage small, and the user space will auto-expand if it needs more space. The entire application keeps everything as small as possible.

                        Note: My cpu is fast enough that sometimes all 5 timestamp entries have the same value. If you call the program a few times, you will eventually see one of the entries jump to a different timestamp. But dont be surprised if all of the timestamp entries are indentical.
                        Last edited by MichaelCatalani; August 24, 2010, 09:00 PM.
                        Michael Catalani
                        IS Director, eCommerce & Web Development
                        Acceptance Insurance Corporation
                        www.AcceptanceInsurance.com
                        www.ProvatoSys.com

                        Comment


                        • #13
                          Re: Arrays as parameter in RPLGE

                          Originally posted by MichaelCatalani View Post
                          Those changes are picked up automatically on a re-compile.
                          You make that sound easy but it can be a pain if you've got hundreds of programs calling your procedure. All of the programs become inextricably linked making go-lives pretty laborious and suceptible to mistakes. This is known as "high coupling" where different modules have a high dependancy on one another. It is the opposite of "low coupling" which is the more desirable.

                          I tend to favour a service program with a procedure for each value rather than a data structure. Let's say I want to return an array of customers, the code calling the service program might look like this:
                          PHP Code:
                            CUST_InitialiseSearch//subset or position parameters );
                            
                          Dow CUST_getNextCustomer();
                              
                          index+=1;
                              
                          customers(index).name CUST_getName();
                              
                          customers(index).address CUST_getAddress();
                              ...
                            
                          EndDo
                          This model exhibits low coupling. If I wanted to I could add a new field to the customer file and I would only have to recompile that CUST service program. If one of the programs needed to access the new field then I could add one more procedure to the service program which that calling program could then use. The previous service program signature will continue to be exported so all of the existing programs that don't need this new field would contine to work without the need for a recompile.

                          I have also seen approaches where one passes a data structure to a procedure but its a major pain when you want to change the data structure. You are working on the assumption that you have one program library where you can compile anything you like. However, if you are a vendor writing a framework that is being used by different people then you can't impose on them a full system recompile everytime they want to upgrade. It needs to be backwards compatable.
                          Ben

                          Comment


                          • #14
                            Re: Arrays as parameter in RPLGE

                            Also, because the actual business logic is contained in this one service program, you can change it at any time and you only have to recompile that one service program. It may be that you decide that addresses should have their own file. In that case you could create the new file and change the service program. All the calling programs will continue to use those same procedures as they don't have to care about the business rules. If every program was compiled over the file structure then you would have major surgery on your hands.
                            Ben

                            Comment


                            • #15
                              Re: Arrays as parameter in RPLGE

                              You make that sound easy but ...
                              I wouldn't say it sounds easy if it takes 5 posts to explain it

                              Ben I think your first reply was plenty! Yes, you can pass an array as a parm.
                              Your friends list is empty!

                              Comment

                              Working...
                              X