Rabu, 03 April 2013

AS/400 Chapter 7: Modules and Procedures

Implementing modules can be extremely useful, especially in big applications because it allows the reuse of code in a fairly simple manner.
A module is an executable program's component. When we compile a module's source code we don't get an executable file, but a unit that when connected to other units results in the executable object.
A module can have on or more procedures. A procedure is like a function. You can pass parameters to it and return values.
One of the advantages of modules is the possibility of reusing the code, since you can use a module as a component of several different executable objects.

Creating modules

We're going to create two modules and then connect them into an executable object.
What the modules will do: the main module sends a client's birth date to a procedure in the other module and this procedure will return the age of the client. We're going to calculate the age of all the clients.
Let's start with the main module. Create an SQLRPGLE member called MAIN_MOD.
Define a date variable to store the birth date (name it birth) and a numeric one to store the age (name it age).
Let's build a cursor to go through all the records in the CLIENTS table. For the cursor we need 4 subroutines:

Declaring the cursor (subroutine name: declareCursor)

DECLARE CURSOR1 CURSOR FOR SELECT BIRTH_CLI
FROM DEMO/CLIENTS

Opening the cursor (openCursor)

OPEN CURSOR1

Fetching values from the cursor (fetchCursor)

FETCH CURSOR1 INTO :birth

Closing the cursor (closeCursor)

CLOSE CURSOR1
Now for the main block of the code, call the subroutine to declare the cursor and to open it. Then, inside a cycle, fetch values from the cursor like this:
exSr fetchCursor;
dow sqlcod <> 100;
    ...
    exSr fetchCursor;
enddo;
Or:
dow sqlstt = '00000';
    exSr fetchCursor;
    ...
enddo;
sqlcod and sqlstt variables store the state from the last SQL instruction performed. Sqlstt = '00000' means success, while sqlcod = 100 means the last instruction didn't retrieve any data.
More info on these codes.
Let's close this module and create the second module with the procedure that calculates the age.
Create a new RPGLE type member named CALC_AGE.
On the first line of this member should be HNOMAIN, starting at the first SEU column. This means that this module won't be a main module.

Procedures

Now we're going to see how to declare a procedure and its parameters.
A procedure is delimited by:
Pname_proc B EXPORT
Dname_proc PI 3i 0
Dparameter1 D
  
...code declarations
  
P E

Line 1

Beginning of the procedure, with a P starting the line. The B (begin) defines the beginning of the procedure and the E (end) at line 4 defines its end. The EXPORT keyword makes this procedure public to other modules. If it didn't have this keyword it could only be used inside this module.

Line 2

The name of the procedure is repeated this time in a D specification. In this line the return type is declared. The return type of this procedure is “3i 0” - an integer of length 3 with 0 decimal places. If the procedure doesn't return any value, declare this line without the return type. In this case you wouldn't declare “3i 0”.

Line 3

Defines a parameter. A procedure can have more than one parameter and each one should be declared in a different line. By default the parameter is passed by reference. To pass a parameter by value we use the VALUE keyword in the functions field. With the CONST keyword the parameter is passed by reference and its value can't be altered in the procedure.

Line 7

End of procedure. Now you can define the beginning and end of the CALC_AGE procedure (it has the same name as the file but it could have another name). The procedure will receive a date by parameter and return an integer - define them. Outside the parameter definition declare an auxiliary variable to store the age (name it age). When you're through with this, check if it looks like what we have bellow, and add line 6 to your code:
Dage S 3P 0
PCALC_AGE B EXPORT
dCALC_AGE PI 3i 0
Db_date D
/free
age = %diff (%date() : b_date : *years);
return age;
/end-free
P E 

Line 6

The %date() function returns the system date. The %diff function calculates the difference between two dates (%date() and bdate) in years (*years). Notice how the values are separated by a colon (:). This is the parameter separator used in RPG. It's just like the comma used in C++ or Java. For more information on manipulating dates in RPG check this site.

Line 7

Returns the value. There is still one detail missing in the declaration of procedures. Every time we declare a procedure or we need to call it from another module we must place the procedure's prototype in the D specification of the file. This procedure's prototype:
DCALC_AGE         PR             3i 0
Db_date                           D
So, you must put these lines in the CALC_AGE file (before or after the declaration of the age variable). You declare it there and on the MAIN_MOD file, because you need to call this procedure there.
Notice de declaration of the return type and the parameters on the prototype. These values must match those on the beginning of the procedure.
     *
     HNOMAIN
     *
     Dage S 3P 0
  
     DCALC_AGE PR 3i 0
     Db_date D
     *
     PCALC_AGE B EXPORT
     dCALC_AGE PI 3i 0
     Db_date D
      /free
          age = %diff (%date() : b_date : *years);
          return age;
      /end-free
     P                 E
Back to MAIN_MOD, we're going to declare the procedure's prototype and call it. You should have something like this:
     Dbirth s d
     Dage s 3i 0
      /free
           exsr declareCursor;
           exsr openCursor;
           exsr fetchCursor;
  
           dow sqlcod <> 100;
               exsr fetchCursor;
           enddo;
           exsr closeCursor;
  
           *inlr = *on;
           return;
      /end-free
  
     *
     * sub-routines declaration
     *
Declare the prototype exactly the same way as you declared it on the CALC_AGE file. Inside the cycle you must call the procedure:
age = CALC_AGE(birth);
The cycle should look like this:
dow sqlcod <> 100;
    age = CALC_AGE(birth);
    dsply age;
    exsr fetchCursor;
enddo;

Compiling modules

Compile the two members (MAIN_MOD and CALC_AGE) with PDM's option “15-Create module” (this is the one you should always use to compile modules). After compiling the modules, connect them into an executable file, as we show you next.

Creating programs from modules

You connect modules with the command:
CRTPGM(PGM_NAME) MODULE(MAIN_MOD MOD1 MOD2...)
The first module on the modules' list is always assumed to be the main one. In this case, MAIN_MOD is the program's main module.
To call the program from the system prompt:
CALL PGM_NAME

Tidak ada komentar:

Posting Komentar