Static and dynamic CALL, CANCEL and ON EXCEPTION
How does the called program actually get into memory? There are two answers, and which one your shop uses affects how changes are deployed.
Static calls
With a static call, the subprogram's object code is link-edited into the caller's load module. One load module contains both. The call is fast and can't fail at run time, but if the subprogram changes, every program that includes it must be link-edited again to pick up the change.
On IBM Enterprise COBOL, CALL "LITERAL" is static when the caller is
compiled with the NODYNAM option.
Dynamic calls
With a dynamic call, the subprogram is its own load module. The first
CALL finds it in the load libraries and loads it; later calls reuse the
loaded copy. Replace the module in the library and the next run picks up
the new version without touching any caller. Most large shops call their
shared routines dynamically for exactly that reason.
A call is dynamic when:
- the caller is compiled with
DYNAMand usesCALL "LITERAL", or - the program name is in a data item:
CALL WS-PGM. This is always dynamic, because the name isn't known until run time.
CALL identifier lets a program pick the routine from its data: one
rating module per insurance product, one validation module per country.
GnuCOBOL, which runs your code here, loads separately compiled
subprograms dynamically for both forms.
CANCEL
CANCEL "NAME" (or CANCEL WS-PGM) releases a dynamically called
program. The next CALL loads a fresh copy, so its WORKING-STORAGE is
back to its VALUE clauses. You can list several names in one CANCEL.
Cancelling a program that was never called does no harm.
ON EXCEPTION
If a dynamic CALL can't find the module, the run unit fails. GnuCOBOL
prints libcob: error: module 'NOSUCH' not found; on z/OS the step
abends with S806. When the program name comes from data, that is a
real possibility, so trap it:
IDENTIFICATION DIVISION.
PROGRAM-ID. DYNDEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-PGM PIC X(8).
PROCEDURE DIVISION.
MOVE "COUNTER" TO WS-PGM
CALL WS-PGM
CALL WS-PGM
CANCEL WS-PGM
CALL WS-PGM
MOVE "NOSUCH" TO WS-PGM
CALL WS-PGM
ON EXCEPTION
DISPLAY "CANNOT LOAD " WS-PGM
END-CALL
DISPLAY "STILL RUNNING"
STOP RUN.
IDENTIFICATION DIVISION.
PROGRAM-ID. COUNTER.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-N PIC 9(3) VALUE 0.
PROCEDURE DIVISION.
ADD 1 TO WS-N
DISPLAY "COUNTER CALL " WS-N
GOBACK.
END PROGRAM COUNTER.
END PROGRAM DYNDEMO.
COUNTER CALL 001
COUNTER CALL 002
COUNTER CALL 001
CANNOT LOAD NOSUCH
STILL RUNNING
NOT ON EXCEPTION runs when the call did work. Close the statement with
END-CALL.
A trap: DISPLAY has ON EXCEPTION too
DISPLAY accepts its own ON EXCEPTION and NOT ON EXCEPTION phrases.
Write this:
CALL "NOSUCH"
ON EXCEPTION
DISPLAY "MISSING"
NOT ON EXCEPTION
DISPLAY "LOADED"
END-CALL
and the compiler attaches NOT ON EXCEPTION to the DISPLAY, not the
CALL. The program prints MISSING and LOADED. Put the work in
paragraphs (PERFORM 3000-NO-MODULE), or close the DISPLAY with
END-DISPLAY.
On the job
An S806 in the job log means "module not found": usually a program
promoted without its subprogram, or a STEPLIB/JOBLIB that points
at the wrong load library. It's one of the first abend codes you will
learn to recognise.
Your task
An insurer prices quotes in batch. Each product has its own rating
subprogram, and the name of the module is the product code in the
request. Today RATEHOME and RATEMOTR exist; any other product has no
module yet. Both share one interface:
LINKAGE SECTION.
01 LS-SUM PIC 9(7)V99.
01 LS-PREMIUM PIC 9(7)V99.
01 LS-QUOTE-NO PIC 9(3).
PROCEDURE DIVISION USING LS-SUM LS-PREMIUM LS-QUOTE-NO.
Each module numbers its quotes from 001 in its own WORKING-STORAGE.
Complete QUOTEBAT. For each request line (8-character product code,
then 9 digits of sum insured):
NEWDAY: display--- NEW DAY ---andCANCELboth rating modules so their quote numbers start again at 001.- otherwise
CALLthe module named inWS-PRODUCTwith the sum, premium and quote number. If it loads,PERFORM 2000-SHOW-QUOTE. If it can't be loaded, count it inWS-REJECTEDand display the product code followed byNO RATING MODULE.
The input
06
RATEHOME030000000
RATEMOTR001500000
RATEHOME045000000
RATEPETS000080000
NEWDAY
RATEHOME020000000
produces
RATEHOME Q001 PREMIUM 900.00
RATEMOTR Q001 PREMIUM 550.00
RATEHOME Q002 PREMIUM 1350.00
RATEPETS NO RATING MODULE
--- NEW DAY ---
RATEHOME Q001 PREMIUM 600.00
QUOTED 004 REJECTED 001