Search code examples
ibm-midrangerpg

RPG program parm change impact analysis


I have a situation where an RPG program used as an API needs to be modified. I am trying to do an impact analysis of this change to avoid any errors in dependant programs.

So, the program has two parameters. Both these parms are data structures.

The requirement is to add one new field to the input parm DS and one field to the output parm DS.

The API program (which is being changed) entry is defined as this:

dcl-pi;
    InputDS    likeds(API901INP);
    OutputDS   likeds(API901OUP);
end-pi;

Below is an example of how the input and output DS's in the API program are defined and how they are going to be changed by adding the new field:

dcl-ds InputDS extname('901_i);
    NameOfCandidate extfld('name');
    JobOfCandidate extfld('job'); --> newly added field
    AgeOfCandidate extfld('age');
end-ds;

dcl-ds OutputDS extname('901_o');
    AgeQualified extfld('qualified');
    JobCertified extfld('certified'); --> newly added field
end-ds

As can be seen, the standard we use requires API DS structures to be defined as an external structure. Which means, if a new field is to be added as above, the reference tables (901_i/901_o) would need to be modified first.

Also, when this API is called from within other programs, the DS would have to be defined using the reference files.

Now, the question is not all programs calling the API need the new field added to the DS. So, would the existing programs be impacted by this change?

And to repeat, the existing programs also use the same external reference files (901_i/901_o) to define the datastructure parms to be used when calling the API program. So, would they (calling programs which dont add the new field in output and input DS) need a change of some sort, say recompilation etc ?

Update: The above was just a simplified example of what I need to do. Below is the actual code.

This is how the input DS is defined in the API rpg.

dcl-ds P_IAC3003I                          extname('IAC3003_I') qualified template;
    ExternSessionId                          extfld('EXTSESSID');
    WorkKey                                  extfld('WORKKEY');
    PreferedReferenceType                    extfld('PREFREF');
    SalesCountryCode                         extfld('SALESCNTRY');
    ManufacturingCountryCode                 extfld('MANUFCNTRY');
    TypeOfPerformanceUsage                   extfld('PERFUSE');
    TypeOfMechanicalUsage                    extfld('MECHUSE');
    UsageDateChar                            extfld('USAGEDATE');
    DistributionDateChar                     extfld('DISTRDATE');
    PerfIPRight                              extfld('PERFRIGHT');
    MechIPRight                              extfld('MECHRIGHT');
    DistributingSociety                      extfld('DISTRSOC');
    TypeOfAction                             extfld('SAVEACTION');
    UserPermission                           extfld('USERPERM');
    ExpertMode                               extfld('EXPERTMDE');
    LimitAccessToSociety                     extfld('LMTACCSSOC'); //new field
    GetNoOfRows                              extfld('GETNOOFROW');
  end-ds;  

The new field (LimitAccessToSociety) was not added as the last field as by convention, the getNumberOfRows is always passed as the last parm (I think it makes cosmetic sense to maintain it that way).

This is how a caller would call the RPG:

callp IAC3003 (IACSESSION:
                  IAC3003I:
                  IACRETMSG:
                  IAC3003D:
                  IAC3003L1:
                  IACRESLIST01:
                  IAC3003L2:
                  IACRESLIST02:
                  IAC3003L3:
                  IACRESLIST03);   

The first parm being the one to which the new field is to be added.


Solution

  • The problem if you don't want to compile every program that calls the API program is that the callee has to know if the caller knows about the new field or not, otherwise the callee maybe fail if the age parameter has to be numeric, at least would not use the age as the caller passed it and maybe would corrupt the caller memory which could hide the real problem behind a exception in the caller.

    You could add a third parameter that tells the version of the API with options(*nopass), and when the parameter is not set (%parms = 2) act like it was set to the orginal version

    But the problem is that the new field in the input parameter is not added at the end, so next compilation of the caller has to have the new parameter passed and set because the new input structure is used and the age value has moved.

    I'm not sure it's worth the effort.

    Edit :

    how does the ds field values get passed correctly after recompile ?

    Since the structure is defined after IAC3003_I, an external file, every change to the file makes the structure change in every program that is compiled after the file is changed, and only when the program is compiled