Under the following headings are a selection of practical examples of SELCOPY Batch syntax. Please click on the headings to view.
For futher examples and help on other topics, please vist our FAQ page.
The simplest of functions you can perform with
SELCOPY are file copies.
The following is a SELCOPY program which does this:
READ A WRITE B
The above represent the minimum elements required
for a SELCOPY program. One selection (READ)
must cause input, and one selection (WRITE)
must cause output.
In this case, SELCOPY will READ one logical record from file A and then copy it to file B. The READ/WRITE cycle is repeated until all of the records from file A are exhausted (i.e. end of file is reached) at which point, by default, SELCOPY will automatically terminate.
In addition to the control cards shown, a link must be provided between the filenames mentioned to SELCOPY (Files A & B in the above example) and the physical datasets to which they refer. These are:
- DD statements for MVS users,
- FILEDEF statements for CMS users, and
- TLBL, DLBL, EXTENT and ASSGN statements for VSE users.
Alternatively, SELCOPY will dynamically allocate files using a dataset name provided either as a literal or from a position in its work area. e.g.
READ A DSN='SEQUENTIAL.INPUT.FILE' VOL=SYSWK1 WRITE B DSN=44 AT 1001 CAT=UCAT1 VSAM
Almost as simple are SELCOPY's selection and modification capablities. For example:
RD INFILE * Read a record IF POS 10 = 'CR' * Select records with CR in col 10 THEN PRINT STOPAFT=10 * and print only the first 10 THEN WRITE CRFILE * and write all of them to CRFILE IF POS ANY = 'PICK ME' * Scan whole rec for PICK ME THEN POS @ = 'PICKED ' * change it to PICKED THEN WRITE PKFILE * and create a file of picked ELSE WRITE NOTPK * plus file of not picked
Selection criteria can be as simple or as complex as
The above example illustrates use of IF/THEN/ELSE logic, but further conditions can be stipulated based on the result of a previous one with the use of THENIF/ELSEIF. Nesting can therefore easily be achieved in a structured and understandable manner.
For many applications, you will need more space than
taken up by your file input record in order to store
and manipulate data or counters, build new records
For this purpose SELCOPY enables you to request a number of bytes which can be used as a sort of "scratch pad".
RD INFILE WORKLEN 300 * Read a record (say Lrecl=150) into POS 1 IF POS 10 NE POS 201 LEN 4 * Test for a change in Cost Centre. THEN MOVE 4 FR 10 TO 201 * Store in workarea for comparison. THEN PR FR 201 L 4 * Print list of different Cost Centres.
In this example we read a file of records sorted by Cost Centre code, held in a 4 byte alpha-numeric field at position 10, and print out a list of each different code.
Changing record formats is another example of the ease
of coding SELCOPY control statements.
A Master file of customer records is kept on tape. Each record holds 40 bytes of fixed information for the customer in the first part of the record, and variable information at the end. The average record length is 600 bytes.
It is a requirement to produce a file containing only the fixed data, to reduce run times during small 'batch windows'. The abbreviated file is to be blocked to 32000 bytes.
READ TAPE RECFM=V WRITE TAPE1 LRECL=40 BLKSIZE=32000 RECFM=F
Note that SELCOPY will automatically strip off the 4 bytes of control information when copying from variable to fixed length records.
Often, the information contained in files consists of
data which is not readily printable - e.g. packed
decimal, binary or hexadecimal fields.
SELCOPY will allow you to view parts of or whole records, areas of your work area, or indeed any of SELCOPY's special fields, in order to recognise non-character data. The normal printout produced by the PRINT commands in a SELCOPY program is basically geared to problem solving by programmers. You can however, easily produce reports for non-programming staff.
The SELCOPY reference manual contains several types of print format, three of which (Types MC,B & D), are illustrated below:-
Example: PRINT TYPE=MC (Mixed - predominantly char with hex)
SELCOPY REL 9.8P AT CBL - Bridgend UK (Internal Only) (OS) VM/CMS=VM03 14.05 WED 09 DEC 1998 PAGE 1 o ----------------------------------------------------- -------------------------------------- -------- o o 1. rd INDD o 2. print type=mc * Mixed - Char if printable, else Hex o o INPUT SEL SEL 1 RECORD RECNO TOT ID. 1 2 3 4 5 6 7 8 9 0 LENGTH o ----- --- --- ....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0 ------ o 1 1 2 0Fred Bloggs,1Sunshine House,1Sunshine Street,0Sunny Village,0Sunny Valley,1Sunnington-on-Thames 96 o D 0 1 F E 5 o 2 2 2 0Joe Bloggs,1Thunder Mountain,0Rain Town,0Snowy Creek,0Windy City,0Hail-on-Sea 78 o C 2 B D C C o ....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0 o SUMMARY.. o SEL-ID SELTOT FILE BLKSIZE LRECL FSIZE CI DSN ------ ------ ---- ------- ----- ----- -- --- o 1 2 READ INDD 96 96 U 2 SBR.TEST.A1 o 2 2 o o ** ** ** ** ** ** ** SELCOPY IS LICENSED BY COMPUTE (BRIDGEND) LTD +44 (1656) 652222 & 656466 ** ** ** ** ** ** ** ** EXPIRY DATE -- 12 JUN 2001 **
Example: PRINT TYPE=B (Both char and hex)
SELCOPY REL 9.8P AT CBL - Bridgend UK (Internal Only) (OS) VM/CMS=VM03 14.05 WED 09 DEC 1998 PAGE 1 o ----------------------------------------------------- -------------------------------------- -------- o o 1. rd INDD o 2. print type=b * Both Char & Hex, Line 1-Char, 2-Zone, 3-Numeric. o o INPUT SEL SEL 1 RECORD RECNO TOT ID. 1 2 3 4 5 6 7 8 9 0 LENGTH o ----- --- --- ....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0 ------ o 1 1 2 Fred Bloggs, Sunshine House, Sunshine Street, Sunny Village, Sunny Valley, Sunnington-on-Thames 96 o 0C9884C9988A61EA9A88984C9AA861EA9A88984EA988A60EA99A4E89988860EA99A4E8998A61EA99898A996996E8898A o D69540236772B024528955086425B1245289550239553BF2455805933175BE245580513358B524559573650650381452 o 2 2 2 Joe Bloggs, Thunder Mountain, Rain Town, Snowy Creek, Windy City, Hail-on-Sea 78 o 0D984C9988A61E8A98894D9A9A88960D8894E9A960E99AA4C988960E898A4C8AA60C8896996E88 C1650236772B23845459046453195BB919503665BD25668039552BC6954803938BC81930650251 o ....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0 o SUMMARY.. o SEL-ID SELTOT FILE BLKSIZE LRECL FSIZE CI DSN o ------ ------ ---- ------- ----- ----- -- --- 1 2 READ INDD 96 96 U 2 SBR.TEST.A1 o 2 2 o o ** ** ** ** ** ** ** SELCOPY IS LICENSED BY COMPUTE (BRIDGEND) LTD +44 (1656) 652222 & 656466 ** ** ** ** ** ** ** o ** EXPIRY DATE -- 12 JUN 2001 **
Example: PRINT TYPE=D (Dump format)
SELCOPY REL 9.8P AT CBL - Bridgend UK (Internal Only) (OS) VM/CMS=VM03 14.05 WED 09 DEC 1998 PAGE 1 o ----------------------------------------------------- -------------------------------------- -------- o o 1. rd INDD o 2. print type=d o o INPUT SEL SEL RECNO TOT ID. o ----- --- --- o 1 1 2 96 0000 0DC69985 8440C293 968787A2 6B10E2A4 95A28889 958540C8 96A4A285 6B11E2A4 *.Fred Bloggs,.Sunshine House,.Su* o 0020 95A28889 958540E2 A3998585 A36B0FE2 A49595A8 40E58993 93818785 6B0EE2A4 *nshine Street,.Sunny Village,.Su* o 0040 9595A840 E5819393 85A86B15 E2A49595 899587A3 96956096 9560E388 819485A2 *nny Valley,.Sunnington-on-Thames* 2 2 2 78 o 0000 0CD19685 40C29396 8787A26B 12E388A4 95848599 40D496A4 95A38189 956B0BD9 *.Joe Bloggs,.Thunder Mountain,.R* o 0020 81899540 E396A695 6B0DE295 96A6A840 C3998585 926B0CE6 899584A8 40C389A3 *ain Town,.Snowy Creek,.Windy Cit* 0040 A86B0CC8 81899360 969560E2 8581 *y,.Hail-on-Sea * o o SUMMARY.. SEL-ID SELTOT FILE BLKSIZE LRECL FSIZE CI DSN o ------ ------ ---- ------- ----- ----- -- --- o 1 2 READ INDD 96 96 U 2 SBR.TEST.A1 2 2 o o ** ** ** ** ** ** ** SELCOPY IS LICENSED BY COMPUTE (BRIDGEND) LTD +44 (1656) 652222 & 656466 ** ** ** ** ** ** ** o ** EXPIRY DATE -- 12 JUN 2001 ** o
Where logic is required to bypass or repeat operations,
the GOTO statement can be used.
The following example processes a tape file with a logical record length of 38, and block size of 3160. The file consists of two different types of records:
- A header record, is always numeric in position 1 and 2.
- A transaction record, always has 'Z' in position 1.
The file is in ascending sequence of header records,
but many header records may have the same number in
positions 1 and 2.
It is required to select only the header records containing '81' in position 1 and 2, together with their associated 'Z' records, writing them to tape with an output blksize of 380.
At the same time we require a print of all the '81' Header records that were selected.
READ TAPE10 LRECL=38 * LRECL reqd for VSE only. IF POS 1 NE '81' THEN GOTO GET * Implicit label for 1st logical stmt. ==LOOP== ** Only '81' records drop through to here ** WRITE TAPE11 BLKSIZE=380 IF POS 1 NE 'Z' THEN PRINT STOPAFT=222 * Limit printing READ TAPE10 * No need to repeat LRECL. IF POS 1 GT '81' * 'Z' is < '8' THEN GOTO EOJ GOTO LOOP * Prevent automatic GOTO GET. =LOOPE= * Unref'd label. '=' for readability only
The THEN GOTO GET statement will cause looping around the first READ statement until we find a record with 81 in position 1. On finding it, control will drop through to LOOP, our main loop.
Because (for EBCDIC) "Z" is lower than numerics, checking position 1 for greater than "81" will never be satisfied by a transaction record. So we keep looping around until either we get End-of-file, or we find a record with 82 or more in position 1 and 2.
Storing data on disk is extremely inefficient when the data consists of many embedded blanks and other duplicated characters. To avoid this inefficiency, the COMPRESS/EXPAND facility has been introduced, allowing compression before writing, and expansion back to the full record size after reading a compressed record.
READ BIGFILE NORDW WORKLEN=2222 * Ignore the 4-byte RDW. COMPRESS FR 1 TO 1001 * Compress LRECL bytes. WR TAPEFIL FR 1001 RECFM=VB B=32000 L=4096 * Write Back-up.
The CAT statement:
Concatenation of input files is beneficial to MVS, VSE and CMS users, as any type of file may be concatenated. e.g. a sequential disk file, a VSAM file, a Card reader file, a Library Directory file, and even a VTOC file. No restrictions on record format, record length or blocksize.
READ SEQDISK CAT DBAAAA00 DL1 SEG=DBAAAA01 * A DL1 data base. CAT CARD CAT LIB2DD DIR * A PDS directory. CAT TAPE10 * A magnetic tape. CAT ABCFILE KSDS WRITE BIGFIL * Your reqd RECFM etc.
CAT Example for VSE:
An example for VSE users is to read a standard MVS labelled tape containing 2 logical data sets, processing everything (all 6 physical data sets) as data by reading the tape as unlabelled using NL, No Label. An MVS data set on tape consists of 3 sections, each one terminated by a Tape Mark which denotes physical EOF (End-of-File) for a VSE unlabelled tape.
- The 1st section contains two 80-byte Header records for the data set, and on the 1st data set on the tape volume this section will also contain one 80-byte Volume label preceding the HDR records.
- The 2nd section contains the data records for the data set which may be of any length up to 32760 bytes.
- The 3rd section contains two 80-byte Trailer records for the data set.
Thus the 2 data sets constitute 6 unlabelled VSE files, which we will read as one file using the CAT statement. Note that TLBL cards are not required for unlabelled tapes.
// ASSGN SYS010,X'280' // ASSGN SYS011 etc up to SYS015, all to the same drive. // EXEC SELCOPY READ TAPE10 NL CLOSE=NORWD B=80 RECFM U CAT TAPE11 NL OPEN=NORWD CLOSE=NORWD B=32760 RECFM U CAT TAPE12 NL OPEN=NORWD CLOSE=NORWD B=80 RECFM U CAT TAPE13 NL OPEN=NORWD CLOSE=NORWD B=80 RECFM U CAT TAPE14 NL OPEN=NORWD CLOSE=NORWD B=32760 RECFM U CAT TAPE15 NL OPEN=NORWD B=80 RECFM U IF LRECL = 80 * Check length of current record. THEN IF P 2 = 'VOL' !OR P 2 = 'HDR' !OR P 2 = 'TRL' THEN PRINT TYPE M * Statistics info. THEN GG * GOTO GET if reqd. WRITE BIGFIL RECFM U LRECL 32760 * Make a Disk copy. /*
CAT Example for MVS:
An example for MVS users is to concatenate
several associated files of different types. e.g.
A RECFM=FB unlabelled tape file, a RECFM=VB file
and a VSAM ESDS on different disk types. This
mixture of files cannot be concatenated using JCL.
Assuming DD statements for TAPE1, DISK1, DISK2, SYSPRINT and SYSIN:
READ TAPE1 RECFM=FB L=46 INTO 11 WORKLEN 222 CAT DISK1 * Recfm, Blksize & Lrecl known to system. CAT DISK2 ESDS * Must identify as VSAM ESDS IF IN 1 !THEN MOVE 8 FR FNAME TO 1 * Current filename. IF POS 11 = 'CUST' * Test pos 1 of inp rec. THEN LRECL = L+10 * Allow for filename THEN PRINT * Print Customers only.
CMS and VSE users may access directory and
data records for generic groups of files and MVS users
may access all members of single or concatenated PDSs,
using the DIRDATA input facility.
CMS and MVS users may also Update-in-place, but for VSE an update file must be written out and used subsequently as input to a LIBR step.
For Data records SELCOPY's INCOUNT value is reset to 1 on reading the first data record from each library member or CMS file. For Directory records the INCOUNT value is simply increased by 1 to reflect the count of library members or CMS files. Directory and Data records are distinguishable using the IF DIR/IF DATA syntax.
MVS Summary of PDS Members:
A PDS contains a large number of CLISTs and REXX procedures which conventionally contain within the 1st 10 records a timestamp, level number and a short description of their purpose and call parameters. We will create a compendium of the descriptive text, spacing 2 lines between each member.
NOPRINT * Suppress print of ctl cards etc. READ INPDS DIRDATA * Read all PDS members. IF DIR * If it's a Dir record. THEN SPACE 2 * Print 2 blank lines. THEN PR TYPE=M * Use Mixed print for binary recstats. THEN GOTO GET * Means go to 1st logical statement. IF INCOUNT <= 10 * Select 1st 10 DATA recs THEN PRINT * Use default TYPE=N ELSE FLAG EOMEMB * Force to read next member.
CMS Generic Update:
An EXEC procedure becomes outdated and is replaced by another with a different name. All other EXEC's which call this need therefore to be updated to call the new name.
READ '* EXEC *' DIRDATA * Read all EXEC files. IF DIR * If it's a Dir record. AND POS 77 NE 'R/W' * Can't update if disk is read-only. THEN FLAG EODISK * Indicate End of Disk THEN GOTO GET * Bypass rest of disk. IF POS ANY = 'EXEC ABC' * Name of old EXEC. THEN POS @ = 'EXEC XYZ' * Change name THEN UPDATE '* EXEC *' * and update the file.
The above could easily be improved so that it prints the name of each file modified, and the names of the read-only files left unchanged.
VSE Library Generic Backup
This example will backup all payroll associated PROCEDURE and PHASE members from a VSE Library to a single tape file.
READ LIB1.SUB.PAY.* DIRDATA * Read all payroll files. IF DIR * If it's a Dir record. THENIF POS ANY = 'PHASE' * Further selection. OR POS ANY = 'PROC' THEN DUMMY * Do nothing. ELSE FLAG EOMEMB * Indicate End of Member. THEN GOTO GET * Will bypass data rec's. WR TAPEFIL RECFM=VB LRECL=4096 BLKSIZE=32000 * Copy to tape.
Back-up 6 small VSAM files to a single tape volume without the usual multi-file volume difficulties and dangers.
Use SELCOPY to prefix a one-byte file identifier to each record and write all files to the same tape file, one after the other. Write RECFM=V output, blocked to device capacity, 32760. The overhead of 5 bytes for each record (4 for RDW and 1 for File Id) is more than compensated by the large blocksize. Use of NORDW on the restore suppresses the RDW from the input area. Omitting JCL for defining files, the SELCOPY control cards are below.
SELCOPY treats lower case as upper case unless in 'quotes', the Exclamation Mark is a Line End Character, and valid abbreviations used are:
rd read w worklen fr from l lrecl b blksize t then pr print p pos ty type s stopaft li elseif ti thenif
VSAM is specified throughout for simplicity, but the same principle works for any file. RECFM, LRECL and BLKSIZE would be needed for VSE, but not for MVS and CMS as the operating system supplies this, as does VSAM.
equ LMAX 4000 * Maximum record length. read F1 ksds into 102 w=LMAX+110 * GS009 DOC * cat F2 esds * INTO effective on all CAT's. cat F3 ksds * 2nd char of filename used as identifier. cat F4 esds cat F5 rrds cat F6 vsam * More CAT statements can be added. move 1 fr fname+1 to 101 * Set File Identifier (2nd char of filename). lrecl = L+1 * Add 1 to record length of current record. wr TAPE10 recfm=v b=32760 fr=101 do PRINTIT * Print sample of data backed up. goto get * GET is implicit label - 1st ctl stmt. ==PRINTIT== * Subrtn only coded for additional info on printer * if p 6 ne p 101 len 1 * same File Id No? t p 1 = 'File x --- started.' s 1 t move 1 fr 101 to 6 * Save File Id No. t space 2 !t pr l 30 * Print file id msg. if p 101 = '1' !t pr fr 101 ty=b s=3 * Print 1st 3 recs, Both char+hex. li p 101 = '2' !t pr fr 101 ty=b s=3 * and the same for F2 li p 101 = '3' !t pr fr 101 ty=b s=3 * and F3 li p 101 = '4' !t pr fr 101 ty=b s=3 * etc. li p 101 = '5' !t pr fr 101 ty=b s=3 li p 101 = '6' !t pr fr 101 ty=b s=3 =ret= * Return to statement following DO PRINTIT.
Restore All Files:
rd TAPE10 recfm v nordw blksize=32760 lrecl = L-1 * Reduce record length. if p 1 = '1' !t wr F1 ksds fr 2 li p 1 = '2' !t wr F2 ksds fr 2 li p 1 = '3' !t wr F3 esds fr 2 li p 1 = '4' !t wr F4 esds fr 2 li p 1 = '5' !t wr F5 rrds fr 2 li p 1 = '6' !t wr F6 vsam fr 2
Restore Just One File:
rd TAPE10 recfm v nordw blksize=32760 if p 1 lt '3' !t goto get * GET is implicit label - 1st ctl stmt. if p 1 gt '3' !t eoj * Force eoj when finished with file 3. lrecl = L-1 write F3 esds fr 2
A file of JCL statements, OLDJCL, needs modification
to numerous DSN fields, all of which are on the first
line of the DD card. The file REPJCL contains
just DD cards which are in any sequence, and any match of
any DD name in OLDJCL must be substituted with the
appropriate record from REPJCL. Other records are to
remain unchanged, and the file NEWJCL is to be
SELCOPY treats lower case as upper case unless in 'quotes', the Exclamation Mark is a Line End Character, and the following abbreviations are used:
w worklen p pos l lrecl t then fr from wr write
//SELC5BLD JOB (0414OSVBT00),CLASS=A, // MSGCLASS=X,MSGLEVEL=(1,1) //ALTER EXEC PGM=SELCOPY //SYSPRINT DD SYSOUT=* //OLDJCL DD DSN=SELC5.OS.JCL(P7077),DISP=SHR //REPJCL DD DSN=SELC5.DSN.JCL3,DISP=SHR //NEWJCL DD DSN=SELC5.OS.JCL(P7077A),DISP=SHR //SYSIN DD * option w=80000 * Large workarea. equ ARRAY 4001 * Store area for REPJCL recs. equ ARRAYEND 79900 * End of array. @ = ARRAY * Set @ ptr to start of array. ==LOOP1== * Once only * Read whole of Base Data Set into an array. read REPJCL into @ * Read into array elem. if eof REPJCL then @END = @ * Save ptr to end of array. then goto LOOP1E * Go read 2nd file. @ = @+80 * Add 80 to @ ptr. if @ > ARRAYEND * If array is full. then goto cancel goto LOOP1 =LOOP1E= * LOOP1 end * ==LOOP2== *(Main Loop)* read OLDJCL * Read 2nd input file. if eof OLDJCL !t eoj * Go to successfull End-of-Job. * Match this OLDJCL record against all REPJCL records * using substitute record for output where appropriate. if p ARRAY+2,@END = 8 at 3 step=80 * Scan for DDNAME match. then wr NEWJCL fr @-2 * If same DD, use Substitute. else wr NEWJCL fr 1 * Write out orig record. goto LOOP2 * To read next record. =LOOP2E= * LOOP2 end * (Unreferenced label.)
In the above SELCOPY control cards, use is made of both the standard @ pointer and a user @ pointer which for convenience we have chosen to call @END.
The @ ptr is invaluable in giving a fixed reference point to a previously undefined position in your work area. It can be set either explictly by the assignment @ = 20 for instance, or implicitly by a successful range test. e.g. IF P 20 30 = ABC STEP=1 where STEP indicates the increment over the range for each subsequent compare. (STEP=1 is actually the default and needn't be coded)
Offsets may be obtained by coding @+n or @-n, where n is the offset required.
A very large CMS library needs modification to the directory
date to force reorganisation.
Record 1 of the file holds the Directory record number as a 2 byte binary field at position 38. In the Directory record, position 107 contains a date in YYMMDD format which must change to set the Day number to zero. The year is 95, so we can verify this before the update.
XEDIT says it's too large.
EXECIO says the lrecl is greater than 256.
COPY says insufficient disk space - and anyway it takes too long.
SELCOPY will fix it!
Just key it in:
l lib1 usrlib b ( alloc FILENAME FILETYPE FM FORMAT LRECL RECS BLOCKS LIB1 USRLIB B1 F 8192 8200 16400 R; SELC READ LIB1.USRLIB.B READ LIB1.USRLIB.B REC 2 AT 38 TY B IF P 107 '95' THEN P 111 '00' THEN UPDATE LIB1.USRLIB.B THEN LOG FR 101 LEN 50 TYPE B THEN STOP ELSE GOTO CANCEL INPUT OUTPT SEL RECNO RECNO ID. 1 2 3 4 5 ----- ----- --- ....,....0....,....0....,....0....,....0....,....0 0 2 1 5 950700 USRLIB Q w 48 000000FFFFFF00EDCDCC0E0100DE00040EA0B000FF05000022 00001095070001474392CF09018E005A3F63710048FF000009 R;
Or write an EXEC:
* NEWDAY EXEC * +++ LEVEL 002 +++ 94/04/21 17:07:32 +++ * Alters library's directory date to force REORG. FILEDEF LIB DISK LIB1 USRLIB B &BEGSTACK read LIB * Read 1st record. read LIB rec 2 at 38 ty b * Read specific record if p 1 = '--- KEY/REC NOT FOUND ---' then log '+++ DIR POINTER INVALID +++' then goto cancel if p 107 ones '000000' * Date will be numeric. and p 107 ge '75' le 2 at date * Check for valid Year. and p 109 ge '01' le '12' * Check for valid Month. and p 111 ge '01' le '31' * Check for valid Day. then p 111 = '00' * All OK - Zeroise Day No then update lib * Rewrite record to disk. then print type b * Print whole record, both char and hex. then eoj else log '+++ EXISTING DATE INVALID +++' then goto cancel &END &STACK EXEC SELC &EXIT &RETCODE
SYSIBM.SYSCOLUMNS is the DB2 table which describes every column of every table within a DB2 SubSystem. For our example we'll list from it a few columns of interest for a specified table and use the CHAR option to return all information in displayable character format.
read F1 tab=SYSIBM.SYSCOLUMNS char \ fmt='name,TBNAME,TBCREATOR,COLNO,COLTYPE,LENGTH,SCALE' \ where="TBNAME='TYPE_TEST'" \ order='colno' print * Print the row.
The code for this SQL operation is quite long, so we have
used the SELCOPY statement continuation feature. The
continuation character is a backslash (\) as the
last character of a control statement.
The following is output from the above control cards with a subroutine added which generates column headings by analysing the SQL Descriptor Area using the SELCOPY positional keyword SQLDA.
SELCOPY REL 9.80 AT CBL-VMPS31 MVS 5.2.2 OS JOB=P390A 13.47 WED 14 MAY 1997 PAGE 1 o ---------------------------------------- -------------------------------------- -------- o o ** CBL.SSC.CTL(DB2SBR2) *** L=101 +++ 97/05/14 13:47:19 (P390A) o * Demonstrate Table Column listing. o o equ hd 1001 opt w 2222 o o rd f1 tab=sysibm.syscolumns char \ fmt='name,TBNAME,TBCREATOR,COLNO,COLTYPE,LENGTH,SCALE' \ o where="TBNAME='TYPE_TEST'" \ o 1. order='colno' o o 2. do heading stopaft=1 o 3. print * Print the row. o 4. goto get o o ==heading== o ------- o 5. @n = 2 at sqlda+14 type=b * Number of cols in use. 6. @sqlv = sqlda+16 * Point to 1st var. o 7. pos uxatptr = 4 at @sqlv+4 * Sets @ -> 1st col in workarea. o 8. @1stc = @ * Keep as @1stc. o =loop= o ---- 9. pos uxatptr = 4 at @sqlv+4 * Sets @ -> this col in workarea. o 10. pos hd+@-@1stc-1 = '|' o 11. pos hd+@-@1stc-1+100 = '|' 12. pos hd+@-@1stc = 18 at @sqlv+14 o o if @n > 1 o 13. then @n=@n-1 o 14. then @sqlv=@sqlv+44 15. then goto loop o o 16. pr fr hd o 17. tran Lrecl at hd+100 ' ' '-' o 18. pr fr hd+100 19. =ret= o o INPUT SEL SEL 1 RECORD o RECNO TOT ID. 1 2 3 4 5 6 7 8 9 0 LENGTH o ----- --- --- ....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0 ------ 1 1 16 NAME |TBNAME |TBCREATO|COLNO |COLTYPE |LENGTH|SCALE 76 o 1 1 18 ------------------|------------------|--------|------|--------|------|------ 76 o 1 1 3 TTINT |TYPE_TEST |P390 | 1|INTEGER | 4| 0 76 2 2 3 TTSINT |TYPE_TEST |P390 | 2|SMALLINT| 2| 0 76 o 3 3 3 TTDEC |TYPE_TEST |P390 | 3|DECIMAL | 7| 2 76 o 4 4 3 TTCHAR |TYPE_TEST |P390 | 4|CHAR | 8| 0 76 5 5 3 TTVCHAR |TYPE_TEST |P390 | 5|VARCHAR | 30| 0 76 o 6 6 3 TTFLOAT |TYPE_TEST |P390 | 6|FLOAT | 8| 0 76 o 7 7 3 TTREAL |TYPE_TEST |P390 | 7|FLOAT | 4| 0 76 ....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0 o o SUMMARY.. SEL-ID SELTOT FILE BLKSIZE LRECL FSIZE CI DSN o ------ ------ ---- ------- ----- ----- -- --- o 1 7 READ F1 76 U 7 2 1 o 3----4 7 o 5----8 1 9---12 7 o 13---15 6 o 16---19 1 o o ** ** ** ** ** ** ** SELCOPY IS LICENSED BY COMPUTE (BRIDGEND) LTD +44 (1656) 652222 & 656466 ** ** ** ** ** ** ** ** EXPIRY DATE -- 12 JUN 2001 **
The following special arguments for the SELCOPY POS keyword are supported:
POS SQLCA Refers to the SQL Communication Area.
POS SQLDA Refers to the SQL Descriptor Area.
POS SQLMA Refers to the SQL Message Area.
We will print a sample of a DL1/IMS Data Base, together with
Segment names and Level numbers, restricting the
print to the first 50 segments.
For clarity, we will space a line on the print every time we hit a Root Segment which is identified by a Level number of 01 in the PCB feedback area.
Fields in DL1's PCB may be referenced using SELCOPY's positional keywords:
|POS PCB||Database Name||8||Char|
|POS PCB+8||Seg Level||2||ZonedDec|
|POS PCB+10||Status Code||2||Char|
|POS STATUS||Synonym for PCB+10|
|POS PCB+12||Processing Options||4||Char|
|POS PCB+20||Segment Name||8||Char|
|POS SEG||Synonym for PCB+20|
|POS PCB+28||Length of Key||4||Binary|
|POS PCB+32||No of Sensitive Segs||2||Binary|
|POS PCB +36||Key Feedback Area||Var||Char|
We will use a work area (automatically initialised to blanks by
SELCOPY) which is larger than the largest record, and read
segments (records) into position 101.
But segments shorter than 100 bytes may have residual data still in the work area from the last segment. This must be cleared with blanks before printing.
POS LRECL in SELCOPY refers to the last byte of the current input record assuming it was read into position 1, but in our case, we read our record into a position 100 bytes further on, so LRECL+100 is the last byte of the current record. It is therefore position LRECL+101 which needs to be blanked. L+101 is a valid abbreviation.
After moving in the Segment Name and Level no to the front of the work area, we will print it, restricting the print length to 200 and spacing one line first if we have a root segment to print. In spite of the restriction of L=200 on the PRINT command, it is still the true segment length of each individual segment which is printed on the right hand side of the SELCOPY report.
The Status Code is not checked because EOF is handled automatically by SELCOPY as well as any major error conditions.
SELCOPY Control Cards
read DBNAME DL1 into 101 w 2222 * Work area length 2222. pos L+101,200 = ' ' * Blank out residual data. move 2 fr pcb+8 to 1 * Segment Level No. move 8 fr seg to 10 * Segment Name. if pos pcb+8 = '01' * Is it a Root Segment? t space 1 * Extra blank line. t p 20 = '*=* ROOT SEGMENT OF DB xxxxxxxx *=*' t move 8 fr pcb to 43 * Data Base name. else pos 20,80 = ' ' print L 200 s 50 * First 50 segs, length 100.
- SELCOPY treats lower case as upper case unless in 'quotes'. Some common abbreviations are:
rd read w worklen fr from l lrecl b blksize t then pr print p pos ty type s stopaft li elseif ti thenif
Change "t space 1 " to " t line 1 " to force a new page. You could also display the Processing Options. Use POS PCB+12.
The following live example illustrates use from TSO's READY message, using the S CLIST (provided on the distribution tape) to invoke SELCOPY, taking its control cards from parameter 1.
Using the command 'S TERM', the CLIST allocates both SYSIN and SYSPRINT to the user's terminal. This type of invocation is ideal for one-off jobs to investigate, for instance, the layout of files, or for simple fixes as shown in the following example.
We wish to read all members of a PDS with the dataset name, 'userid.ABCD', which happens to contain JCL. Where the JCL calls the program IEWL, replace it with a call to the program XXXX. This, of course, is not a real program name but serves as an example.
READY s term /* TO END - ENTER SELCOPY CONTROL CARDS ... rd A dsn=abcd dirdata upd!if p any = 'IEWL'!t p @ = 'XXXX'!t upd A!t pr SELCOPY REL 9.8P AT CBL - Bridgend UK (Internal Only) ----------------------------------------------------- 1. RD A DSN=ABCD DIRDATA UPD IF P ANY = 'IEWL' 2. T P @ = 'XXXX' 3. T UPD A 4. T PR /* INPUT SEL SEL RECNO TOT ID. 1 2 3 4 5 6 ----- --- --- ....,....0....,....0....,....0....,....0....,....0....,....0.. 77 1 4 //LNK EXEC PGM=XXXX,REGION=500K, 76 2 4 //LNK EXEC PGM=XXXX,REGION=500K, 35 3 4 //LNK EXEC PGM=XXXX,REGION=500K, 35 4 4 //LNK EXEC PGM=XXXX,REGION=500K, ....,....0....,....0....,....0....,....0....,....0....,....0.. SUMMARY.. SEL-ID SELTOT FILE BLKSIZE LRECL FSIZE CI DSN ------ ------ ---- ------- ----- ----- -- --- 1 320 READ A 23440 80 FB 4 P390B.ABCD 2 4 3 4 UPD A 23440 80 FB 4 P390B.ABCD 4 4 ** ** ** ** ** ** ** SELCOPY IS LICENSED BY COMPUTE (BRIDGEND) LTD +44 ( ** EXPIRY DATE -- 12 JUN 2001 **) READY
The above example is perfectly good for a controlled example, but has certain short-comings if we consider changing a more commonly used string.
- There is no check to ensure that we don't update directory records.
- Only the first occurence of the string within each record will be modified.
An easier and better (in that it eliminates the deficiencies
above) way to achieve the same update would be to use a REXX
exec called SCANPDS, which is also provided on the SELCOPY
It's syntax is: SCANPDS ddname string1 string2
ddname is the ALLOC for the input PDS
string1 is the string to scan for
string2 if provided is used to overwrite string1, wherever found, and update that PDS member record.
For our example we would key in: SCANPDS abcd IEWL XXXX
MVS, VSE and CMS datasets may be processed without a DD, DLBL or FILEDEF statement by providing the full dataset name on the SELCOPY I/O command, either as a literal or as a field in the workarea giving a variable data set name.
Dynamic allocation has a variety of uses in all environments. A simple application for MVS is shown below, which uses SELCOPY to copy selected members of a PDS to another new PDS. For this example, we will select members with '96' anywhere in the member name.
read PDSINP dsn='CBL.PDS.SSPDSC' dirdata into 101 worklen 33333 * Read directory record and data * records for each PDS member. if dir * If it's a PDS directory record then do SELECTION * then selectively open a new output memb. else write PDSOUT fr 101 * Copy record to the output member. goto get ==SELECTION== ** Process the PDS directory records ** if pos 101,107 = '96' * Select if '96' appears anywhere in the name. then pos 1,44 = 'CBL.PDS.SSPDSC.Y96' stopaft 1 * Output DSN. then pos 45 = '(12345678)' stopaft 1 * Append the then pos 46 = 8 at 101 * memb name. then open PDSOUT dsn = 44+10 at 1 * CLOSE is automatic. else flag eomemb * Suppress the OPEN for this input member. return
- SELCOPY tolerates blanks padding the variable DSN up to 44 bytes and blanks padding the member name up to 8 bytes.
- The SELCOPY feature, DIRDATA, is used to read all DIRectory
and DATA records from the PDS, opening each member in turn,
provided FLAG EOMEMB has not been set.
DIRDATA input for MVS returns the directory record for each member, followed by its data records. (For VSE and CMS, the directory records are reformatted by SELCOPY.) PDS member selection may then be based on any combination of information held in the directory record. e.g. member name, userid, timestamps, record count/file size, authorisation code.
- Although not illustrated above, at the same time, using a few
additional statements, the output member name could have been
changed to rationalize it so that the '96' falls in a fixed
The following SELCOPY/WNT job will generate and dynamically execute File Transfer Program commands to SEND a generic group of files to your mainframe.
Although this example uses an MVS Partitioned Data Set to receive the PC files it could easily be modified for any environment and any FTP command.
Occurrences of %1, %2 and %3 in the control card syntax refer to the parameters passed to SELCOPY/WNT on the invoking command line.
equ pdsname 1 equ dirrec 101 option w 32760 do init stopaft=1 * Initialise once only. rd %1 dir into dirrec * Read a directory rec into pos 101. pos dirrec-1+38 = ' ' * Blank out the '.' pos @fn = 9 at dirrec-1+30 * fn followed by a blank. if p @fn,@fn+9 = ' ' * Bound to get one. then pos @,@fn+10 = ")'" pos dirrec-1+60-5 = 'send ' if lrecl < 80 then pos dirrec+lrecl,dirrec+80 = ' ' then lrecl = 80 * Keep it neat. pos dirrec+lrecl = pos 1,@fn+22 log fr dirrec-1+60-5,dirrec+lrecl-1+@fn+22-1 system fr dirrec-1+60-5,dirrec+lrecl-1+@fn+22-1 * wr ssftp.cmd fr dirrec-1+60-5,dirrec+lrecl-1+@fn+22-1 * To run in OS/2. gg ==init== ** Initialisation sub-routine ** pos pdsname+3 = %2 !lower 1 at pdsname+3 * The emulator session. pos pdsname+3+1 = ":'" * x: pos pdsname+3+3 = %3 * x:receive.pds.name if p pdsname+3,pdsname+99 = ' ' * Scan for blank. then @fn = @+1 lower from pos pdsname+3,@fn * Lower case the dsn. pos @fn-1 = "(ABCDEFGH)' ascii crlf" * x:receive.pds.name(ABCD.. etc =ret=
Assuming that the above control cards are stored in the file d:\cbl\SSFTP.ctl, then keying in at the DOS prompt
selcopy <d:\cbl\SSFTP.ctl c:\dos\*.BAS C CBL.FTPTEST
could generate and execute the following FTP commands:
send c:\dos\GORILLA.BAS c:'cbl.ftptest(GORILLA)' ascii crlf send c:\dos\MONEY.BAS c:'cbl.ftptest(MONEY)' ascii crlf send c:\dos\NIBBLES.BAS c:'cbl.ftptest(NIBBLES)' ascii crlf send c:\dos\REMLINE.BAS c:'cbl.ftptest(REMLINE)' ascii crlf
The command line may seem a little long winded, in which case it would be worthwhile setting up a BAT file: e.g.
:** h:\cg\SSFTP.BAT kkk L=101 --- 97/06/19 11:24:32 (P22) : Format: ssftp fileid_with_wildcard emulator_session mvs_pds_dsn : e.g. ssftp C:\CBL\*.T* B CBL.SELC980.DM selcopy <d:\cbl\ssftp.ctl %1 %2 %3
The following job illustrates use of EXPAND and COMPRESS for CSV data.
Input CSV records are read into position 1 of the workarea and expanded so that all comma separated fields are copied to contiguous, fixed 30 byte fields beginning at position 201.
The expanded fields are printed (datawidth 30) before being re-compressed into a CSV format where hash (#) is used to delimit fields (instead of comma) and all non-numeric fields are enclosed in apostrophes (').
* Expand/Compress CSV example. * * Note: The LRECL value is automatically updated to be the length of the * expanded or compressed data following an EXPAND or COMPRESS operation. * Hence, PRINT FROM x, requires no length. (Prints LRECL bytes by default). * opt worklen=2222 pagedepth=99999 datawidth=30 read CARD fill if incount > 1 then print "------------------------------" then space 3 print "*** --------------------------" print from 1 * The original (compressed) CSV data. space 1 * Expand to fixed length 30 byte fields. * Note that each comma separated source field must be <= 30 bytes. expand Lrecl at 1 to 600 at 201 dlm=',' enc='"' flen 30 print from 201 * The expanded CSV data. space 1 * Re-Compress using "#" to delimit fields (instead of commas) and enclose all * non-numeric fields in single quotes. compress 600 at 201 to 200 at 801 dlm='#' enc="'" str flen 30 print from 801 * The re-compressed CSV data. end 10010001,Mrs,Gaye,Sample,0,Mrs Sample,"""Uppingdene House""",Barham,,,,CANTERBURY,Kent,CT4 6QD,United Kingdom,C 10010002,Mr,Edward,McSample,10,Mr Edward S McSample,23 Sycamore Drive,,,,,AYLESFORD,Kent,ME20 7LB,United Kingdom,C 10010003,Ms,Lisa,Sample,"""""",Ms Lisa Sample,14 St. Stephen's Road,,,,,CANTERBURY,Kent,CT2 7HT,United Kingdom,C 10010004,Mrs,Glynis,Sample,',Mrs Sample,"Railway Cottage, Sandland",Chipstead,,,,SEVENOAKS,Kent,TN13 2SP,United Kingdom,C 10010005,Mrs,Patricia,Sample,,Mrs Sample,Barbican House,St. Stephen's Way,,,,FOLKESTONE,Kent,CT20 3RD,United Kingdom,C 10010006,Mrs,Jennifer,Sample,,Mrs Sample,2 Court Cottages,Flete Road,Manston,,,MARGATE,Kent,CT9 4LP,United Kingdom,C02 10010007,Mrs,Elizabeth,Sample,,Mrs Sample,5 Hever Place,,,,,CANTERBURY,Kent,,United Kingdom,C 10010008,Mr,Christopher,Sample,,Mr Christopher J Sample,12 Croft Way,,,,,SEVENOAKS,Kent,TN13 2JX,United Kingdom,C 10010009,Mrs,Adriana,Sample-Sample,,Mrs Sample-Sample,19 Westway,Pembury,,,,TUNBRIDGE WELLS,,TN2 7EX,United Kingdom,C 10010010,Mrs,Sally,Sample,xxx,Mrs Sample,Woodstock',Pelham Gardens,xxx,xxx,xxx,FOLKESTONE,xxx,CT20 2LF,United Kingdom,C 10010011,Mrs,Susan,Sample,,Mrs Sample,Colleton House,101 North Road,,,,,Kent,CT21 4AS,United Kingdom,C