The Create CLP Extract command creates CL source for use in
extracting data from a record buffer to variables declared from a
data base file format. The CRTCLPDCL command may be used to create
the DCL commands. CRTCLPEXT simplifies the use of a RDDBR command
from the CLPDBR tool. See also the CRTCLPINS command which performs
the inverse function.
Note that as of V5R4, the CL Compiler allows a data structure and
eliminates the need for CRTCLPEXT. See the CRTCLPDCL command.
CRTCLPEXT is intended primarily for use with the CLPDBR tool to allow
reading of data base records from a CL program. CRTCLPEXT works from
a data base file definition. The command may also be helpful when a
record buffer is passed to CL from a HLL program or an externally
described data structure is processed in a CL program.
Steps used with CRTCLPEXT
-------------------------
The typical use of CRTCLPEXT is to create the code needed to work
with the RDDBR command of the CLPDBR tool. If you are not familiar
with CRTCLPEXT, go thru the sample described in the following
section.
The CRTCLPEXT steps are summarized here:
** Create a source member and write CL code such as described in
the sample.
** Use CRTCLPDCL to declare the variables for the externally
described file.
** Use a source editor to move the DCL statements to the DCL
section of the program.
** Use CRTCLPEXT to create the code needed to perform the
extract.
** Use a source editor to 1) Move the DCL statements to the DCL
section of the program 2) Move the linkage code immediately
after the RDDBR statement and 3) Move the EXTRACT subroutine
after a RETURN and before a ENDPGM statement.
Sample use of CRTCLPEXT
-----------------------
The best method of understanding CRTCLPEXT is to use a simple
example. You must be familiar with the CLPDBR tool to understand
this example.
The sample code reads a record from FILEA. You can write a record to
FILEA using the CRTCLPINS sample code. If you have not already done
so, you may want to use CRTCLPINS to write a record with a key of
BBBBB which is used in this CRTCLPEXT sample.
Assume you want a program that will randomly read a record by key in
a data base file and process the data.
Assume the file is named FILEA (this is the same file as used in the
CRTCLPINS sample) and is defined as follows:
A R FILEARCD
A KEY 5
A FLD1 10
A FLD2 3 0
A FLD3 7 2
A K KEY
To use CRTCLPEXT, you would create a CL source member (RDFILEA is
used in this example) in the QCLSRC file with enough structure to get
your program started. Note that the FILEA file name must be entered
into the DBRCTLx files to use OPNDBR.
PGM
OPNDBR FILE(xxx/FILEA) OPNTYPE(*INP) DBRCTLLIB(yyy)
/* Read a record */
RDDBR TYPE(*EQUAL) RCD(&RCD) KEY(BBBBB)
/* Dump the CL pgm to allow view of data */
DMPCLPGM
CLSDBR
RETURN
ENDPGM
This is the only code you need to write. Other code will be
generated for you by use of TAA commands.
The CLPDBR tool's RDDBR command requires a return variable of 5000
bytes. This is much larger than the FILEA record. The RDDBR RCD
parameter is named &RCD to allow you to use the default name on
CRTCLPEXT. The variable will be declared by the use of CRTCLPEXT and
data will be moved from &RCD to a variable that is given the name of
the record format of the file (&FILEARCD in this example). An *EQUAL
type of read is requested with a key of BBBBB. This is the same key
as is written in the CRTCLPINS sample.
In the sample code a DMPCLPGM command is used to allow a display of
the variable data following the read. In normal use, you would have
additional CL statements to process the record.
The next step is to use CRTCLPDCL to create the DCLs that declare the
variables for the fields in FILEA.
CRTCLPDCL FILE(FILEA) SRCMBR(RDFILEA)
CRTCLPDCL generates DCL statements for each field in the file. The
source statements are added at the end of the specified source
member. Using a source editor, move the DCLs to the DCL section of
the program. Your source would look like:
PGM
/* Defined from FILEA in xxx */
/* Start CRTCLPDCL definitions - 09/07/09 */
DCL VAR(&KEY) TYPE(*CHAR) LEN(5)
DCL VAR(&FLD1) TYPE(*CHAR) LEN(10)
DCL VAR(&FLD2) TYPE(*DEC) LEN(3 0)
DCL VAR(&FLD3) TYPE(*DEC) LEN(7 2)
/* End of CRTCLPDCL definitions */
OPNDBR FILE(xxx/FILEA) OPNTYPE(*INP) DBRCTLLIB(yyy)
RDDBR TYPE(*EQUAL) RCD(&RCD) KEY(BBBBB)
/* Dump the CL pgm to allow view of data */
DMPCLPGM
CLSDBR
RETURN
ENDPGM
When RDDBR completes, the data is in the &RCD variable. To process
the data you would have to substring (%SST) from the &RCD variable
into the variables created by CRTCLPDCL. This can be a tedious and
error prone requirement.
To avoid this coding of substring, the CRTCLPEXT tool can be used to
generate the code that will do it for you.
CRTCLPEXT will generate source statements at the end of your existing
source member:
CRTCLPEXT FILE(FILEA) SRCMBR(RDFILEA)
The source that is generated has 3 sections:
** DCL statements that must be moved to the DCL section of the
source.
** Linkage code that is needed to link to a supplied section of
code labeled the EXTRACT routine (described in a later
section). You have to move the statements (beginning with the
comment 'EXTRACT subroutine linkage' to the appropriate place
in your program which in this case is immediately after RDDBR.
Part of the linkage code is to do CHGVAR from &RCD to the
format name of the file you specified.
** The third section is the EXTRACT routine which uses substring
functions to extract from the record buffer to the variables
declared from the data base fields. Packed and zoned fields
that exist in the record buffer require special handling in
the EXTRACT routine (see later discussion). This subroutine
like function is intended to be placed after your RETURN
statement.
The added code looks like:
/* Defined from FILEA in xxx */
/* Start CRTCLPEXT definitions - 09/07/09 */
DCL VAR(&RCD) TYPE(*CHAR) LEN(5000)
DCL VAR(&FILEARCD) TYPE(*CHAR) LEN(21)
DCL VAR(&EXTRTN) TYPE(*CHAR) LEN(8)
DCL VAR(&EXTCHR8) TYPE(*CHAR) LEN(8)
DCL VAR(&EXTHEX0) TYPE(*CHAR) LEN(8) +
VALUE(X'0000000000000000')
DCL VAR(&EXTDEC15) TYPE(*DEC) LEN(15 0)
/* End CRTCLPEXT definitions */
/* Move immediately after a command such as RDDBR */
/* EXTRACT subroutine linkage */
CHGVAR VAR(&FILEARCD) VALUE(&RCD)
CHGVAR VAR(&EXTRTN) VALUE('EXTRACT1')
GOTO CMDLBL(EXTRACT)
EXTRACT1: /* Return from EXTRACT subroutine */
/* Move after a RETURN and before ENDPGM */
SNDESCMSG MSG('Your code has fallen into the +
EXTRACT subr')
/********************************************/
/* */
EXTRACT: /* CRTCLPEXT for FILEA in xxx */
/* Retrieved by CRTCLPEXT on 09/07/09 */
/* */
/********************************************/
CHGVAR VAR(&KEY) VALUE(%SST(&FILEARCD 1 5))
CHGVAR VAR(&FLD1) VALUE(%SST(&FILEARCD 6 10))
CHGVAR VAR(&EXTCHR8) VALUE(&EXTHEX0)
CHGVAR VAR(%SST(&EXTCHR8 7 2)) +
VALUE(%SST(&FILEARCD 16 2))
MOVCHRDEC DECOUT(&EXTDEC15) CHRINP(&EXTCHR8)
CHGVAR VAR(&FLD2) VALUE(&EXTDEC15)
CHGVAR VAR(&EXTCHR8) VALUE(&EXTHEX0)
CHGVAR VAR(%SST(&EXTCHR8 5 4)) +
VALUE(%SST(&FILEARCD 18 4))
MOVCHRDEC DECOUT(&EXTDEC15) CHRINP(&EXTCHR8)
CHGVAR VAR(&FLD3) VALUE(&EXTDEC15 / 100)
/* Return GOTOs. Modify as required */
IF COND(&EXTRTN *EQ 'EXTRACT1') +
THEN(GOTO CMDLBL(EXTRACT1))
SNDESCMSG MSG('Bad return in EXTRACT routine of ' +
*CAT &EXTRTN)
/********************************************/
/* */
/* End of EXTRACT subroutine */
/* */
/********************************************/
Using a source editor, you then:
** Move the DCLs to the DCL section of the program.
** Move the linkage code immediately after RDDBR.
** Move the EXTRACT subroutine after the RETURN command.
** Delete the excess blank separator lines and extra comments.
The final code would look like:
PGM
/* Defined from FILEA in xxx */
/* Start CRTCLPDCL definitions - 09/07/09 */
DCL VAR(&KEY) TYPE(*CHAR) LEN(5)
DCL VAR(&FLD1) TYPE(*CHAR) LEN(10)
DCL VAR(&FLD2) TYPE(*DEC) LEN(3 0)
DCL VAR(&FLD3) TYPE(*DEC) LEN(7 2)
/* End of CRTCLPDCL definitions */
/* Defined from FILEA in xxx */
/* Start CRTCLPEXT definitions - 09/07/09 */
DCL VAR(&RCD) TYPE(*CHAR) LEN(5000)
DCL VAR(&FILEARCD) TYPE(*CHAR) LEN(21)
DCL VAR(&EXTRTN) TYPE(*CHAR) LEN(8)
DCL VAR(&EXTCHR8) TYPE(*CHAR) LEN(8)
DCL VAR(&EXTHEX0) TYPE(*CHAR) LEN(8) +
VALUE(X'0000000000000000')
DCL VAR(&EXTDEC15) TYPE(*DEC) LEN(15 0)
/* End CRTCLPEXT definitions */
OPNDBR FILE(xxx/FILEA) OPNTYPE(*INP) DBRCTLLIB(yyy)
/* Read a record */
RDDBR TYPE(*EQUAL) RCD(&RCD) KEY(BBBBB)
/* EXTRACT subroutine linkage */
CHGVAR VAR(&FILEARCD) VALUE(&RCD)
CHGVAR VAR(&EXTRTN) VALUE('EXTRACT1')
GOTO CMDLBL(EXTRACT)
EXTRACT1: /* Return from EXTRACT subroutine */
/* Dump the CL pgm to allow view of data */
DMPCLPGM
CLSDBR
RETURN
SNDESCMSG MSG('Your code has fallen into the +
EXTRACT subr')
/********************************************/
/* */
EXTRACT: /* CRTCLPEXT for FILEA in xxx */
/* Retrieved by CRTCLPEXT on 09/07/09 */
/* */
/********************************************/
CHGVAR VAR(&KEY) VALUE(%SST(&FILEARCD 1 5))
CHGVAR VAR(&FLD1) VALUE(%SST(&FILEARCD 6 10))
CHGVAR VAR(&EXTCHR8) VALUE(&EXTHEX0)
CHGVAR VAR(%SST(&EXTCHR8 7 2)) +
VALUE(%SST(&FILEARCD 16 2))
MOVCHRDEC DECOUT(&EXTDEC15) CHRINP(&EXTCHR8)
CHGVAR VAR(&FLD2) VALUE(&EXTDEC15)
CHGVAR VAR(&EXTCHR8) VALUE(&EXTHEX0)
CHGVAR VAR(%SST(&EXTCHR8 5 4)) +
VALUE(%SST(&FILEARCD 18 4))
MOVCHRDEC DECOUT(&EXTDEC15) CHRINP(&EXTCHR8)
CHGVAR VAR(&FLD3) VALUE(&EXTDEC15 / 100)
/* Return GOTOs. Modify as required */
IF COND(&EXTRTN *EQ 'EXTRACT1') +
THEN(GOTO CMDLBL(EXTRACT1))
SNDESCMSG MSG('Bad return in EXTRACT routine of ' +
*CAT &EXTRTN)
/********************************************/
/* */
/* End of EXTRACT subroutine */
/* */
/********************************************/
ENDPGM
You can then create the RDFILEA CL program and call it. The spooled
file (QPPGMDMP) created by the DMPCLPGM command should identify the
variables for &FLD1, &FLD2, and &FLD3 that exist in the FILEA record
for a key of BBBBB.
Use of CLPDBR RCLDBR
--------------------
When you begin to use CLPDBR functions along with the EXTRACT
subroutine, it is typical to make mistakes which cause the file you
were operating on to remain open. If you correct the program and
call it again, you will receive an error saying the OPNID is already
in use or open.
To correct the problem you need to use the RCLDBR command which will
delete all of the data areas created by OPNDBR commands, close any
files that are open, and reclaim the activation group that the CLPDBR
functions run in.
Then try your program again.
The Linkage code
----------------
The linkage code begins by moving from the record buffer variable
(&RCD) to the variable assigned to the format name of the data base
file (&FILEARCD). It then sets the value EXTRACT1 into a variable
that will be used in an IF test and branches to the EXTRACT
subroutine. The label EXTRACT1 is used as a return point from the
subroutine.
The EXTRACT subroutine
----------------------
The EXTRACT subroutine uses substring (%SST) to extract the data from
the record buffer and place it in the appropriate variables.
The first statement generated is the SNDESCMSG TAA command which
states that your code has fallen into the subroutine. The subroutine
is intended to be branched to with a GOTO, so the SNDESCMSG command
protects your program logic.
Character data is moved by using substring positions.
Zoned and packed decimal data require specific handling as described
in the next section.
At the end of the subroutine is an IF statement, that determines
where the code should branch to.
If you have one place in your program where you need the subroutine,
the linkage code and ending GOTO appear overly complex. However, the
code is designed to allow multiple uses of the subroutine as is
described in a later section.
The last statement is another SNDESCMSG TAA command which describes
the problem where you have branched to the EXTRACT routine, but do
not have a valid value in &EXTRTN.
Handling of decimal fields
--------------------------
Packed and zoned decimal fields are provided for automatically.
CL does not allow a packed value in a *CHAR variable to be moved to a
*DEC field (CHGVAR would attempt to convert the data as if it were
character). For example, if you have a packed 3 digit field in the
data base the value might be X'123F'. If CHGDTA is used, you would
receive CPF0818 (Value cannot be converted to the receiver).
The TAA MOVCHRDEC tool is used to handle the move from a packed *CHAR
value to a *DEC type variable. Before using MOVCHRDEC, CHGVAR is
used to set a work variable to Hex 00s and then another CHGVAR to
substring from the record data into the Hex 00s field. Following
MOVCHRDEC, a CHGVAR occurs from the &EXTDEC15 variable to your *DEC
variable. &EXTDEC15 is a standard work field declared as *DEC LEN(15
0).
If a packed decimal field has 2 decimal positions, the final CHGVAR
divides by 100 to make a whole number. Unique divisors are used
depending on the number of decimal positions.
CL does not support a zoned decimal type of variable. If a zoned
decimal field had existed in the data base record in the example, a
DCL would define a *DEC variable which is treated as packed decimal
within the CL program. Zoned decimal fields are processed in the
subroutine by first moving the data to the &EXTDEC15 field. As with
packed decimal fields, if more than 0 decimal positions exist, the
final CHGVAR divides by a number such as 100.
Binary fields are declared as *CHAR and CHGVAR is used. You must
supply your own processing of binary data.
Multiple use of the EXTRACT subroutine for the same file
--------------------------------------------------------
The EXTRACT subroutine is designed to allow you to have multiple
points within your program where you need access to a record in the
same file such as the use of additional RDDBR commands.
The following steps are needed for each subsequent use:
** Duplicate the linkage code (shown as follows) just after each
subsequent use of RDDBR:
/* EXTRACT subroutine linkage */
CHGVAR VAR(&FILEARCD) VALUE(&RCD)
CHGVAR VAR(&EXTRTN) VALUE('EXTRACT1')
GOTO CMDLBL(EXTRACT)
EXTRACT1: /* Return from EXTRACT subroutine */
** Change the EXTRACT1 constant in the CHGVAR and the name of the
label. 'EXTRACT2' would be the typical choice for the second
use.
** The last statement in the subroutine is:
IF COND(&EXTRTN *EQ 'EXTRACT1') +
THEN(GOTO CMDLBL(EXTRACT1))
Duplicate this code to the next line and change the 'EXTRACT1' value
on the IF and the THEN to the name you chose previously such as:
IF COND(&EXTRTN *EQ 'EXTRACT2') +
THEN(GOTO CMDLBL(EXTRACT2))
Using both CRTCLPEXT and CRTCLPINS in the same program
------------------------------------------------------
The CRTCLPINS tool provides the inverse function of CRTCLPEXT.
CRTCLPINS provides a subroutine like function to insert data from the
variables declared from the data base fields to a variable declared
as your record format.
You would use CRTCLPINS if you were using a command like WRTDBR or
UPDDBR to write or update a record to the data base.
If you are using both RDDBR and UPDDBR/WRTDBR in the same program,
then both subroutines are needed. Just follow the steps for
CRTCLPINS in addition to CRTCLPEXT. You only need to use the
CRTCLPDCL function once to declare variables for the fields in the
file.
Use of EXTRACT for different files
----------------------------------
You can use CRTCLPEXT for different files within your program, but
you must use a different name for each subsequent use. Use a source
editor to change the name EXTRACT and the corresponding linkage code.
Conversion of field types
-------------------------
Packed and zoned fields are extracted to *DEC variables. A *DEC
field may have up to 15 digits and 9 decimal positions.
Binary fields and all other field types are extracted to *CHAR
variables.
CRTCLPEXT escape messages you can monitor for
---------------------------------------------
None. Escape messages from based on functions will be re-sent.
Command parameters *CMD
------------------
FILE The externally described file to use to create the
extract information from. The file may be either a
PF or LF, but may only contain a single format.
The library defaults to *LIBL. A specific library
or *CURLIB may be entered.
SRCMBR The member of the source file to be added to. The
member must exist. The statements will be added
after the last existing record (if any) in the
source member.
SRCFILE The name of the source file containing the member to
be added to. The source file name defaults to
QCLSRC. The library qualifier defaults to *LIBL. A
specific library or *CURLIB may be entered.
RCDVAR The name of the variable that contains the data
after using a function like RDDBR. The default is
&RCD. The variable is declared as *CHAR LEN(5000)
by CRTCLPEXT. The name is used in a single CHGVAR
statement that is generated at the end of the
linkage code by CRTCLPEXT.
Restrictions
------------
Packed and decimal data base fields must be 15 digits or less and the
number of decimal positions must be 9 or less.
All other field types (including binary) are extracted to character
variables.
** The source file must be at least 92 bytes in length.
Prerequisites
-------------
The following TAA Tools must be on your system:
HLRMVMSG HLL Remove message
RTVDBFA Retrieve data base file attributes
RTVFMT Retrieve format
RTVSYSVAL3 Retrieve system value 3
SNDCOMPMSG Send completion message
SNDDIAGMSG Send diagnostic message
SNDESCINF Send escape information
SNDESCMSG Send escape message
Implementation
--------------
None, the tool is ready to use.
Objects used by the tool
------------------------
Object Type Attribute Src member Src file
------ ---- --------- ---------- ----------
CRTCLPEXT *CMD TAACLRH QATTCMD
TAACLRHC *PGM CLP TAACLRHC QATTCL
TAACLRHR *PGM RPG TAACLRHR QATTRPG
|