A reentrant program has the characteristic of dynamic allocation of space for data and save areas. This reentrant characteristic can be used in assembler programs. In this case, the data and save areas are allocated in a calling (driver) program and passed to a called (reentrant) program as parameters. Storage for these areas need not be allocated in the called program.
A convenient use for reentrancy is the use of an SQLDA structure declared as a DSECT in the calling program. This, in combination with an INCLUDE SQLDA statement in the called program, permits the passing back of values, extracted by a SELECT/FETCH in the called program, in a clean and simple manner. A DESCRIBE statement can be used by the called program to fill the SQLDA structure, or it can be hand-filled in the driver program. Other SQL statements (for example, INSERT, DELETE, UPDATE) utilize a single data location to communicate just an SQLCODE.
If statement results other than the SQLCODE are desired, an SQLCA structure can be allocated in the driver program. However, unlike the SQLDA structure allocation by a DSECT, the fields of the SQLCA structure must be hard-coded into the driver, because the driver will not be preprocessed. An INCLUDE SQLCA statement, within a DSECT, is then required in the called program. SQLCA communication between the two programs can be achieved by passing the address of the first field of the SQLCA structure to the reentrant program.
The "Locda DSECT" structure is hard-coded in the Driver Program, instead of being defined by an "EXEC SQL INCLUDE SQLDA", so that there is no need to preprocess the Driver Program. This example assumes there is only a single host variable returned by the FETCH. For production application programming, it is recommended that macros be created for defining the SQLCA and SQLDA structures (with optional DSECT statement) when used in programs that will not be preprocessed.
The following are skeleton programs illustrating the use of the SQLDA structure, and a single data location for communicating SQLCODEs. The reentrant example illustrates only a FETCH statement. If more than one "action" statement (INSERT, DELETE, and so on) is used, then various flags are needed to direct access to the individual operations. The required modifications to include an SQLCA structure follow these skeletons.
Figure 106. Driver Program
Driver CSECT , Driver Program
* Standard Linkage Conventions ...
STM R14,R12,12(R13) Save callers registers
:
Qstring DC H'57',CL57'SELECT DESCRIPTION FROM INVENTORY WHERE QONHA $
ND < 100' SQL Statement to be executed
:
LA R13,Save1 Subroutine Register Savearea Address
* Forward and backward chain saveareas together
:
LA R4,1 '1' indicates 1st call to subroutine
ST R4,Loccode SQLCODE returned from subroutine
* (Also used as 1st call switch)
:
* Create SQLDA structure to pass to subroutine:
* (OR Subroutine could fill in by using DESCRIBE)
LA R4,LSQLDA Point R4 at SQLDA area
USING Locda,R4 reference SQLDA fields
:
LA R7,Outarea+1 Address where DESCRIPTION stored
ST R7,Locdata
LA R7,Indaddr Address where Indicator Value stored
ST R7,Locind
* NOTE: Setting of other SQLDA fields is not shown, but may be required
:
*
* Loop to call reentrant subroutine (Loop needed for Cursor operation)
LOOP EQU *
*
* Blank Output area for next FETCH result:
:
LA R1,Parmlist Parms passed to subroutine through R1
L R15,=V(Reentran) Load Subroutine Entry Point address
BALR R14,R15 Call Reentrant Subroutine
CLC Loccode,F0 Any error from subroutine ?
BE FetchOK No, continue as normal
CLC Loccode,F100 Cursor EOF occurred ???
BE Final Yes, all done.
B Errchk No, some kind of error, go handle.
*
FetchOK EQU *
* Test indicator values for NULL, etc, and handle as appropriate:
:
*
* Output result from a Fetch: (Data conversion may be necessary)
:
*
* Branch back to Loop for another Fetch
B LOOP
:
Errchk EQU *
* Handle errors returned by subroutine.
:
Final EQU *
* Program complete, restore registers and return to caller
:
BR R14 Return to caller
:
* Declare Section
:
:
F0 DC F'0' 'NO ERRORS' retcode from subroutine
F100 DC F'100' 'CURSOR EOF' retcode from subroutine
:
SaveRA DS 18F register savearea for use by Resource
* ... Adapter when called by subroutine
Save1 DS 18F subroutine register savearea
Loccode DS F SQLCODE variable passed to subroutine
* (return code from subroutine)
:
Parmlist DS 0D Subroutine Parameter List:
DC A(Qstring) SQL Statement to execute
DC A(LSQLDA) Local SQLDA area
DC A(Loccode) Return Code from subroutine
DC A(Hostvar) Host Variable Workarea
DC A(SaveRA) Resource Adapter register savearea
:
Indaddr DS F Indicator area
Outarea DS CL80 Fetch value return area
:
LSQLDA DS CL500 Local SQLDA area
Hostvar DS CL500 Subroutine Host Variable workarea
:
Locda DSECT , Describes SQLDA fields
Locdaid DS CL8
Locdabc DS F
Locn DS H
Locd DS H
Locvar DS 0F assumes one one Host Variable used
Loctype DS H
Loclen DS 0H
Locprcsn DS X
Locscale DS X
Locdata DS A
Locind DS A
Locname DS H,CL30 ...end of Local SQLDA area
:
:
END Driver ...end of Driver Program
Figure 107. Reentrant Program
Reentran CSECT , Reentrant Subroutine
* Standard Linkage Conventions. Register Savearea address in R13.
STM R14,R12,12(R13) Save callers registers
:
* Get Parameter addresses
L R3,0(0,R1) Point to Qstring
L R4,4(0,R1) Point to SQLDA area
USING SQLDA,R4 Reference SQLDA fields
L R5,8(0,R1) Point to Loccode (SQLCODE) return code
USING LSQLCODE,R5 Reference Passed SQLCODE variable
L R6,12(0,R1) Point to Hostvar workarea
USING Hostvar,R6 Reference Hostvar workarea
LR R7,R13 R7 points to callers savearea
L R13,16(0,R1) Point R13 at "our" passed savearea ...
* ... for use by Resource Adapter calls
* Forward and backward chain saveareas together
ST R13,8(0,R7) Caller savearea points to "our" savearea
ST R7,4(0,R13) "our" savearea points to caller savearea
:
* Check if this is first call to subroutine:
CLC F0,0(R5) If NOT zero, it is first call
BE Next Is zero - NOT first call
EXEC SQL CONNECT ...
:
LH R1,0(R3) Get length of Qstring
LA R1,1(R1,0) Length minus 1 for EXecute ...
* ... plus 2 for length Halfword ...
* ... equals length + 1.
EX R1,MOVQSTR move length & Qstring to Hostvar area
EXEC SQL PREPARE S1 FROM :QSTRING
CLC SQLCODE,F0 Any errors ?
BNE Exit Yes, return it to caller
:
* Fill in passed SQLDA structure (possibly with DESCRIBE),
* if not done in Driver program.
:
EXEC SQL DECLARE C1 CURSOR FOR S1
:
EXEC SQL OPEN C1
:
Next EQU *
EXEC SQL FETCH C1 USING DESCRIPTOR SQLDA
CLC SQLCODE,F100 Cursor EOF reached ??
BNE Exit No, return to caller (even if error)
:
*
* All Fetched, Close Cursor before returning
Done EQU *
EXEC SQL CLOSE C1
CLC SQLCODE,F0 Any error ?
BNE Exit Yes, return error to caller
*
* Return 'CURSOR EOF' return code to caller
MVC 0(4,R5),F100 R5 points to Loccode
:
Exit EQU * Return to caller
:
* Restore registers and return to caller
* Our return code is in Loccode
L R13,4(0,R13) Load callers savearea address
LM R14,R12,12(R13) Restore callers registers
BR R14 Return to caller
:
* Declare section
MOVQSTR MVC QSTRING(1),0(R3) EXecuted during 1st call
F0 DC F'0' 'NO ERRORS' retcode from subroutine
F100 DC F'100' 'CURSOR EOF' retcode from subroutine
:
* Include the SQLDA DSECT
EXEC SQL INCLUDE SQLDA
:
Hostvar DSECT , Passed Host Variable Workarea
QSTRING DS CL500
:
LSQLCODE DSECT , Passed SQLCODE variable
SQLCODE DS F
:
END Reentran ...end of Reentrant Subroutine
To include full SQLCA communications between the Driver Program and the Reentrant program, you must modify both programs.
Figure 108. SQLCA Changes for Driver/Reentrant Programs In the Driver program, replace the "Loccode" variable definition with an In the Reentrant program, change from just referencing the "SQLCODE"
"SQLCA" structure definition and update the 3rd address constant in the
"Parmlist", as follows:
:
Save1 DS 18F subroutine register savearea
Locca DS 0D SQLCA structure passed to subroutine
Loccaid DS CL8
Loccabc DS F
Loccode DS F SQLCODE
Locerrm DS H,CL70
Locerrp DS CL8
Locerrd DS 6F
Locwarn DS 0C
Locwarn0 DS CL1
Locwarn1 DS CL1
Locwarn2 DS CL1
Locwarn3 DS CL1
Locwarn4 DS CL1
Locwarn5 DS CL1
Locwarn6 DS CL1
Locwarn7 DS CL1
Locwarn8 DS CL1
Locwarn9 DS CL1
LocwarnA DS CL1
Locstate DS CL5 ... end of local SQLCA structure
:
Parmlist DS 0D Subroutine Parameter List:
DC A(Qstring) SQL Statement to execute
DC A(LSQLDA) Local SQLDA area
DC A(Locca) SQLCA returned from subroutine <----
DC A(Hostvar) Host Variable Workarea
DC A(SaveRA) Resource Adapter register savearea
:
variable, through the "LSQLCODE DSECT", to referencing the full "SQLCA"
structure, through the "PASSEDCA DSECT", as follows:
:
L R5,8(0,R1) Point to Locca (SQLCA) return codes
USING PASSEDCA,R5 Reference Passed SQLCA structure
:
:
PASSEDCA DSECT , Passed SQLCA structure
EXEC SQL INCLUDE SQLCA include SQLCA field definitions
: