Thanks Chris (and Dave and Brian and Alan).
I'll store this in my "important stuff" file and refer to it frequently. Someday maybe I'll be functionally competent.
I doubt that I'll be able to continue my testing until Monday, but with all the help from this list today, I'll have a shot at getting it right.
Much appreciated!
-- Michael
~~~~~~~~~~~~~~~~~
-----Original Message-----
From: rpg400-l-bounces@xxxxxxxxxxxx [mailto:rpg400-l-bounces@xxxxxxxxxxxx] On Behalf Of Hiebert, Chris
Sent: Thursday, October 04, 2012 2:57 PM
To: RPG400-L@xxxxxxxxxxxx
Subject: RE: Troubles with UPDSRVPGM
First of all, Brian is correct, since you listed the modules in the binding directory, your program was created with a copy of the modules.
All the procedures were called from that copy; not from the service program.
When you updated the service program you didn't affect the modules that were copied into the program object.
You could have run the UPGPGM command to get your program to reference the new modules, but this doesn't fix the issue with you referencing the modules instead of the service program from the binding directory.
Here is my current understanding of service programs. Please, anyone, feel free to set me straight if I am mistaken.
When you run CRTSRVPGM the service program is created with a copy of all the modules that were included.
After that, you can change any module without effecting the service program. i.e. no new changes to the module are reflected in the service program. This is the same with creating ILE programs, once the program is created you no longer need the module object other than to recompile the program.
The only way to get the changes to the module to be reflected in the service program is to run a CRTSRVPGM or an UPDSRVPGM.
The UPDSRVPGM will create a replacement object so that users that are still active will be able to continue to reference the old version of the service program.
The CRTSRVPGM has an parameter REPLACE which allows you to choose when to create a replacement object. (Choosing "No" on replace causes the create command to fail.)
After a service program is updated or created you no longer need the modules on the production server.
The binding directory should contain the service program not the modules.
The real trick with service programs comes with how you setup the Export Source File used on the create and update commands Specifically the export file's STRPGMEXP /ENDPGMEXP groups and their associated SIGNATURE entries.
In our shop, we always provide a specific text signature. Some arbitrary like "V1R1M0".
You should never change the order of EXPORT entries unless you want to be required to recompile EVERY program that uses the service program.
If you must change the order, and there is no way around it, then you should create a new STRPGMEXP /ENDPGMEXP group with a new unique text signature and change the old group to PGMLVL(*PRV).
There should only be one STRPGMEXP /ENDPGMEXP group with PGMLVL(*CURRENT), all old groups should have PGMLVL(*PRV ).
When a program is compiled it will always reference the "Current" group to determine procedure exports.
Old programs continue to function because they reference a specific signature from an older (*prv) export group that is still found within the Exported signatures.
A compiled program initially looks up imported procedures by "Name" from the CURRENT group. However, after that they are referenced by "Position"
within the signature's export list. This is why it's important not to change the order of exports and always add new procedures to the end of the list.
It is easiest to maintain one list of exports and always add new procedures to the end of that list.
Each procedure also has a specific prototype that is used at creation time. If you change a procedure's prototype then you must recompile all programs that use that procedure.
There is a way around this issue. Say you have a procedure named "GetName(INT)". You want to change it to "GetName(VARCHAR,INT)".
You want your old programs to continue to run, but they are using "GetName(INT)". What you do is create the procedure "GetName_Deprecated(INT)". And have the procedure call the new GetName.
Then, in all of the existing export lists you change the current "GetName" to "GetName_Deprecated". Then you add the new "GetName" to the end of the Current group.
This will allow new programs to use the "GetName(VARCHAR,INT)" and old programs to continue and use "GetName(INT)".
As long as the old programs are not recompiled they will continue to function by calling GetName_Deprecated whenever they were originally calling GetName.
If you need to recompile one of the old programs you will have to modify it to use the new version of GetName and pass the varchar instead of int as parm 1.
Along these same lines, if you change the order of the exports you could have a program calling the wrong procedure. Say you insert GetLastName before GetName in your exports list, but don't change the signature and don't recompile any programs. Once the service program is created or updated all programs (that have not been recompiled) who were calling GetName will now be calling GetLastName but think they are calling GetName. This can cause really strange results if you don't realize what is happening.
Chris Hiebert
Programmer/Analyst
Disclaimer: Any views or opinions presented are solely those of the author and do not necessarily represent those of the company.
-----Original Message-----
From: rpg400-l-bounces@xxxxxxxxxxxx
[mailto:rpg400-l-bounces@xxxxxxxxxxxx] On Behalf Of Koester, Michael
Sent: Thursday, October 04, 2012 10:30 AM
To: RPG400-L@xxxxxxxxxxxx
Subject: Troubles with UPDSRVPGM
Before I get too far into creating production objects without understanding what I'm doing, I need help with something pretty
fundamental: Like how to update a module and not have to recompile the world after doing so. Or at least knowing what steps ensure that the new object will be used across the application.
I've created some RPG-ILE and SQLRPG modules, and created a service program that "contains" them by listing each module in the MODULES parameter on the CRTSRVPGM command. I created a binding directory that lists each module. I then created a test program (with an H-spec specifying the BNDDIR) to call a few of those modules. I compiled and tested the test program. So far so good.
I modified some logic (without changing the interface) in one of the called modules, recreated the module object, and saw that the module was updated in the BNDDIR. I used UPDSRVPGM to get that change registered in the service program. I signed off my session that I was testing in (per suggestions from midrange archives), and signed back on to verify that the changes would appear when I ran my test program.
The test program appears to use the former copy of the module.
I've been very deliberate about putting all the objects in the same library, and restricting my library lists, so I think it's more a matter of my not understanding what I need to do and how I need to do it.
If I recompile the test program, the new copy is called, but I was hoping that wouldn't be necessary. I'm hoping to have these modules available to many other programs without going through that. I've not messed with binder language yet, but again, I haven't made any changes to the interface.
Our CSM is home-grown (circa 1992) and knows nothing of ILE stuff. And there's no chance of getting a commercial product to replace it here in my lifetime.
OS is at 7.1
Thanks.
Michael Koester
As an Amazon Associate we earn from qualifying purchases.
This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact
[javascript protected email address].
Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.