Rational Developer for System z
Enterprise PL/I for z/OS, Version 3.8, Programming Guide

Using a SEQUENTIAL file to access an ESDS

You can open a SEQUENTIAL file that is used to access an ESDS with either the INPUT or the UPDATE attribute. If you use either of the options KEY or KEYTO, the file must also have the KEYED attribute.

Sequential access is in the order that the records were originally loaded into the data set. You can use the KEYTO option on the READ statements to recover the RBAs of the records that are read. If you use the KEY option, the record that is recovered is the one with the RBA you specify. Subsequent sequential access continues from the new position in the data set.

For an UPDATE file, the WRITE statement adds a new record at the end of the data set. With a REWRITE statement, the record rewritten is the one with the specified RBA if you use the KEY option; otherwise, it is the record accessed on the previous READ. You must not attempt to change the length of the record that is being replaced with a REWRITE statement.

The DELETE statement is not allowed for entry-sequenced data sets.

Defining and loading an ESDS

In Figure 35, the data set is defined with the DEFINE CLUSTER command and given the name PLIVSAM.AJC1.BASE. The NONINDEXED keyword causes an ESDS to be defined.

The PL/I program writes the data set using a SEQUENTIAL OUTPUT file and a WRITE FROM statement. The DD statement for the file contains the DSNAME of the data set given in the NAME parameter of the DEFINE CLUSTER command.

The RBA of the records could have been obtained during the writing for subsequent use as keys in a KEYED file. To do this, a suitable variable would have to be declared to hold the key and the WRITE...KEYTO statement used. For example:

DCL CHARS CHAR(4);
WRITE FILE(FAMFILE) FROM (STRING)
 KEYTO(CHARS);

Note that the keys would not normally be printable, but could be retained for subsequent use.

The cataloged procedure IBMZCBG is used. Because the same program (in Figure 35) can be used for adding records to the data set, it is retained in a library. This procedure is shown in the next example.

Figure 35. Defining and loading an entry-sequenced data set (ESDS)
 //OPT9#7  JOB
 //STEP1    EXEC   PGM=IDCAMS,REGION=512K
 //SYSPRINT DD SYSOUT=A
 //SYSIN    DD    *
      DEFINE CLUSTER -
       (NAME(PLIVSAM.AJC1.BASE) -
       VOLUMES(nnnnnn) -
       NONINDEXED -
       RECORDSIZE(80 80) -
       TRACKS(2 2))
 /*
 //STEP2  EXEC IBMZCLG
 //PLI.SYSIN      DD *
    CREATE: PROC OPTIONS(MAIN);

       DCL
         FAMFILE FILE SEQUENTIAL OUTPUT ENV(VSAM),
         IN FILE RECORD INPUT,
         STRING CHAR(80),
         EOF BIT(1) INIT('0'B);

       ON ENDFILE(IN) EOF='1'B;

       READ FILE(IN) INTO (STRING);
       DO I=1 BY 1 WHILE (¬EOF);
         PUT FILE(SYSPRINT) SKIP EDIT (STRING) (A);
         WRITE FILE(FAMFILE) FROM (STRING);
         READ FILE(IN) INTO (STRING);
       END;

       PUT SKIP EDIT(I-1,' RECORDS PROCESSED')(A);
     END;
 /*
 //LKED.SYSLMOD  DD  DSN=HPU8.MYDS(PGMA),DISP=(NEW,CATLG),
 //         UNIT=SYSDA,SPACE=(CYL,(1,1,1))
 //GO.FAMFILE DD   DSNAME=PLIVSAM.AJC1.BASE,DISP=OLD
 //GO.IN      DD     *
 FRED                     69          M
 ANDY                     70          M
 SUZAN                    72          F
 /*

Updating an ESDS

Figure 36 shows the addition of a new record on the end of an ESDS. This is done by executing again the program shown in Figure 35. A SEQUENTIAL OUTPUT file is used and the data set associated with it by use of the DSNAME parameter specifying the name PLIVSAM.AJC1.BASE specified in the DEFINE command shown in Figure 35.

Figure 36. Updating an ESDS
 //OPT9#8   JOB
 //STEP1    EXEC  PGM=PGMA
 //STEPLIB   DD   DSN=HPU8.MYDS(PGMA),DISP=(OLD,KEEP)
 //          DD   DSN=CEE.SCEERUN,DISP=SHR
 //SYSPRINT  DD   SYSOUT=A
 //FAMFILE   DD   DSN=PLIVSAM.AJC1.BASE,DISP=SHR
 //IN        DD   *
 JANE                     75          F
 //

You can rewrite existing records in an ESDS, provided that the length of the record is not changed. You can use a SEQUENTIAL or KEYED SEQUENTIAL update file to do this. If you use keys, they can be the RBAs or keys of an alternate index path.

Delete is not allowed for ESDS.

Key-sequenced and indexed entry-sequenced data sets

The statements and options allowed for indexed VSAM data sets are shown in Table 28. An indexed data set can be a KSDS with its prime index, or either a KSDS or an ESDS with an alternate index Except where otherwise stated, the following description applies to all indexed VSAM data sets.

Table 28. Statements and options allowed for loading and accessing VSAM indexed data sets
File
declaration1
Valid statements, with
options you must include
Other options you can
also include
SEQUENTIAL OUTPUT
BUFFERED
WRITE FILE(file-reference)
FROM(reference)
KEYFROM(expression);
 
LOCATE based-variable
FILE(file-reference)
KEYFROM(expression);
 
 
 
 
SET(pointer-reference)
SEQUENTIAL INPUT
BUFFERED
READ FILE(file-reference)
INTO(reference);
 
READ FILE(file-reference)
SET(pointer-reference);
 
READ FILE(file-reference);2
KEY(expression) or
KEYTO(reference)
 
KEY(expression) or
KEYTO(reference)
 
IGNORE(expression)
SEQUENTIAL UPDATE
BUFFERED
READ FILE(file-reference)
INTO(reference);
 
READ FILE(file-reference)
SET(pointer-reference);
 
READ FILE(file-reference);2
 
WRITE FILE(file-reference)
FROM(reference)
KEYFROM(expression);
 
REWRITE FILE(file-reference);
 
 
DELETE FILE(file-reference)
KEY(expression) or
KEYTO(reference)
 
KEY(expression) or
KEYTO(reference)
 
IGNORE(expression)
 
 
 
 
 
FROM(reference) and/or
KEY(expression)
 
KEY(expression)
DIRECT
BUFFERED
READ FILE(file-reference)
INTO(reference)
KEY(expression);
 
READ FILE(file-reference)
SET(pointer-reference)
KEY(expression);
 
DIRECT OUTPUT
BUFFERED
WRITE FILE(file-reference)
FROM(reference)
KEYFROM(expression);
 
DIRECT
BUFFERED
READ FILE(file-reference)
INTO(reference)
KEY(expression);
 
READ FILE(file-reference)
SET(pointer-reference)
KEY(expression);
 
REWRITE FILE(file-reference)
FROM(reference)
KEY(expression);
 
DELETE FILE(file-reference)
KEY(expression);
 
WRITE FILE(file-reference)
FROM(reference)
KEYFROM(expression);
 
Notes:
  1. The complete file declaration would include the attributes FILE and RECORD. If you use any of the options KEY, KEYFROM, or KEYTO, you must also include the attribute KEYED in the declaration.
  2. The statement READ FILE(file-reference); is equivalent to the statement READ FILE(file-reference) IGNORE(1);
  3. Do not associate a SEQUENTIAL OUTPUT file with a data set accessed via an alternate index.
  4. Do not associate a DIRECT file with a data set accessed via a nonunique alternate index.
  5. DELETE statements are not allowed for a file associated with an ESDS accessed via an alternate index.
Loading a KSDS or indexed ESDS

When a KSDS is being loaded, you must open the associated file for KEYED SEQUENTIAL OUTPUT. You must present the records in ascending key order, and you must use the KEYFROM option. Note that you must use the prime index for loading the data set; you cannot load a VSAM data set via an alternate index.

If a KSDS already contains some records, and you open the associated file with the SEQUENTIAL and OUTPUT attributes, you can add only records at the end of the data set. The rules given in the previous paragraph apply; in particular, the first record you present must have a key greater than the highest key present on the data set.

Figure 37 shows the DEFINE command used to define a KSDS. The data set is given the name PLIVSAM.AJC2.BASE and defined as a KSDS because of the use of the INDEXED operand. The position of the keys within the record is defined in the KEYS operand.

Within the PL/I program, a KEYED SEQUENTIAL OUTPUT file is used with a WRITE...FROM...KEYFROM statement. The data is presented in ascending key order. A KSDS must be loaded in this manner.

The file is associated with the data set by a DD statement which uses the name given in the DEFINE command as the DSNAME parameter.

Figure 37. Defining and loading a key-sequenced data set (KSDS)
 //OPT9#12  JOB
 //   EXEC  PGM=IDCAMS,REGION=512K
 //SYSPRINT  DD  SYSOUT=A
 //SYSIN     DD  *
    DEFINE CLUSTER -
      (NAME(PLIVSAM.AJC2.BASE) -
      VOLUMES(nnnnnn) -
      INDEXED -
      TRACKS(3 1) -
      KEYS(20 0) -
      RECORDSIZE(23 80))
 /*
 //   EXEC IBMZCBG
 //PLI.SYSIN      DD *
  TELNOS: PROC OPTIONS(MAIN);

         DCL DIREC FILE RECORD SEQUENTIAL OUTPUT KEYED ENV(VSAM),
             CARD CHAR(80),
             NAME CHAR(20) DEF CARD POS(1),
             NUMBER CHAR(3) DEF CARD POS(21),
             OUTREC CHAR(23) DEF CARD POS(1),
             EOF BIT(1) INIT('0'B);

         ON ENDFILE(SYSIN) EOF='1'B;

         OPEN FILE(DIREC) OUTPUT;

         GET FILE(SYSIN) EDIT(CARD)(A(80));
         DO WHILE (¬EOF);
         WRITE FILE(DIREC) FROM(OUTREC) KEYFROM(NAME);
         GET FILE(SYSIN) EDIT(CARD)(A(80));
         END;

        CLOSE FILE(DIREC);

         END TELNOS;
 /*
 //GO.DIREC  DD  DSNAME=PLIVSAM.AJC2.BASE,DISP=OLD
 //GO.SYSIN  DD  *
 ACTION,G.           162
 BAKER,R.            152
 BRAMLEY,O.H.        248
 CHEESEMAN,D.        141
 CORY,G.             336
 ELLIOTT,D.          875
 FIGGINS,S.          413
 HARVEY,C.D.W.       205
 HASTINGS,G.M.       391
 KENDALL,J.G.        294
 LANCASTER,W.R.      624
 MILES,R.            233
 NEWMAN,M.W.         450
 PITT,W.H.           515
 ROLF,D.E.           114
 SHEERS,C.D.         241
 SUTCLIFFE,M.        472
 TAYLOR,G.C.         407
 WILTON,L.W.         404
 WINSTONE,E.M.       307
 //
Using a SEQUENTIAL file to access a KSDS or indexed ESDS

You can open a SEQUENTIAL file that is used to access a KSDS with either the INPUT or the UPDATE attribute.

For READ statements without the KEY option, the records are recovered in ascending key order (or in descending key order if the BKWD option is used). You can obtain the key of a record recovered in this way by means of the KEYTO option.

If you use the KEY option, the record recovered by a READ statement is the one with the specified key. Such a READ statement positions the data set at the specified record; subsequent sequential reads will recover the following records in sequence.

WRITE statements with the KEYFROM option are allowed for KEYED SEQUENTIAL UPDATE files. You can make insertions anywhere in the data set, without respect to the position of any previous access. If you are accessing the data set via a unique index, the KEY condition is raised if an attempt is made to insert a record with the same key as a record that already exists on the data set. For a nonunique index, subsequent retrieval of records with the same key is in the order that they were added to the data set.

REWRITE statements with or without the KEY option are allowed for UPDATE files. If you use the KEY option, the record that is rewritten is the first record with the specified key; otherwise, it is the record that was accessed by the previous READ statement. When you rewrite a record using an alternate index, do not change the prime key of the record.

Using a DIRECT file to access a KSDS or indexed ESDS

You can open a DIRECT file that is used to access an indexed VSAM data set with the INPUT, OUTPUT, or UPDATE attribute. Do not use a DIRECT file to access the data set via a nonunique index.

If you use a DIRECT OUTPUT file to add records to the data set, and if an attempt is made to insert a record with the same key as a record that already exists, the KEY condition is raised.

If you use a DIRECT INPUT or DIRECT UPDATE file, you can read, write, rewrite, or delete records in the same way as for a KEYED SEQUENTIAL file.

Figure 38 shows one method by which a KSDS can be updated using the prime index.

Figure 38. Updating a KSDS
 //OPT9#13  JOB
 //STEP1  EXEC IBMZCBG
 //PLI.SYSIN      DD *
  DIRUPDT: PROC OPTIONS(MAIN);

          DCL DIREC FILE RECORD KEYED ENV(VSAM),
              ONCODE BUILTIN,
              OUTREC CHAR(23),
              NUMBER CHAR(3) DEF OUTREC POS(21),
              NAME CHAR(20) DEF OUTREC,
              CODE CHAR(1),
              EOF BIT(1) INIT('0'B);

          ON ENDFILE(SYSIN) EOF='1'B;

          ON KEY(DIREC) BEGIN;
           IF ONCODE=51 THEN PUT FILE(SYSPRINT) SKIP EDIT
                             ('NOT FOUND: ',NAME)(A(15),A);
           IF ONCODE=52 THEN PUT FILE(SYSPRINT) SKIP EDIT
                            ('DUPLICATE: ',NAME)(A(15),A);
           END;

          OPEN FILE(DIREC) DIRECT UPDATE;

        GET FILE(SYSIN) EDIT (NAME,NUMBER,CODE)
          (COLUMN(1),A(20),A(3),A(1));
        DO WHILE (¬EOF);
        PUT FILE(SYSPRINT) SKIP EDIT (' ',NAME,'#',NUMBER,' ',CODE)
        (A(1),A(20),A(1),A(3),A(1),A(1));
        SELECT (CODE);
           WHEN('A') WRITE FILE(DIREC) FROM(OUTREC) KEYFROM(NAME);
           WHEN('C') REWRITE FILE(DIREC) FROM(OUTREC) KEY(NAME);
           WHEN('D') DELETE FILE(DIREC) KEY(NAME);
           OTHERWISE PUT FILE(SYSPRINT) SKIP EDIT
              ('INVALID CODE: ',NAME) (A(15),A);
        END;
        GET FILE(SYSIN) EDIT (NAME,NUMBER,CODE)
          (COLUMN(1),A(20),A(3),A(1));
        END;

          CLOSE FILE(DIREC);
          PUT FILE(SYSPRINT) PAGE;
          OPEN FILE(DIREC) SEQUENTIAL INPUT;

          EOF='0'B;
          ON ENDFILE(DIREC) EOF='1'B;

          READ FILE(DIREC) INTO(OUTREC);
          DO WHILE(¬EOF);
          PUT FILE(SYSPRINT) SKIP EDIT(OUTREC)(A);
          READ FILE(DIREC) INTO(OUTREC);
          END;
          CLOSE FILE(DIREC);
    END DIRUPDT;
 /*
 //GO.DIREC DD DSNAME=PLIVSAM.AJC2.BASE,DISP=OLD
 //GO.SYSIN DD *
 NEWMAN,M.W.         516C
 GOODFELLOW,D.T.     889A
 MILES,R.               D
 HARVEY,C.D.W.       209A
 BARTLETT,S.G.       183A
 CORY,G.                D
 READ,K.M.           001A
 PITT,W.H.
 ROLF,D.F.              D
 ELLIOTT,D.          291C
 HASTINGS,G.M.          D
 BRAMLEY,O.H.        439C
 /*

A DIRECT update file is used and the data is altered according to a code that is passed in the records in the file SYSIN:

A
Add a new record
C
Change the number of an existing name
D
Delete a record

At the label NEXT, the name, number, and code are read in and action taken according to the value of the code. A KEY ON-unit is used to handle any incorrect keys. When the updating is finished (at the label PRINT), the file DIREC is closed and reopened with the attributes SEQUENTIAL INPUT. The file is then read sequentially and printed.

The file is associated with the data set by a DD statement that uses the DSNAME PLIVSAM.AJC2.BASE defined in the Access Method Services DEFINE CLUSTER command in Figure 37.

Methods of updating a KSDS

There are a number of methods of updating a KSDS. The method shown using a DIRECT file is suitable for the data as it is shown in the example. For mass sequential insertion, use a KEYED SEQUENTIAL UPDATE file. This gives faster performance because the data is written onto the data set only when strictly necessary and not after every write statement, and because the balance of free space within the data set is retained.

Statements to achieve effective mass sequential insertion are:

DCL DIREC KEYED SEQUENTIAL UPDATE
    ENV(VSAM);
WRITE FILE(DIREC) FROM(OUTREC)
 KEYFROM(NAME);

The PL/I input/output routines detect that the keys are in sequence and make the correct requests to VSAM. If the keys are not in sequence, this too is detected and no error occurs, although the performance advantage is lost.

Alternate Indexes for KSDSs or Indexed ESDSs

Alternate indexes allow you to access KSDSs or indexed ESDSs in various ways, using either unique or nonunique keys.

Unique Key Alternate Index Path

Figure 39 shows the creation of a unique key alternate index path for the ESDS defined and loaded in Figure 35. Using this path, the data set is indexed by the name of the child in the first 15 bytes of the record.

Three Access Method Services commands are used. These are:

DEFINE ALTERNATEINDEX

defines the alternate index as a data set to VSAM.

BLDINDEX

places the pointers to the relevant records in the alternate index.

DEFINE PATH

defines an entity that can be associated with a PL/I file in a DD statement.

DD statements are required for the INFILE and OUTFILE operands of BLDINDEX and for the sort files. Care should be taken that the correct names are specified at the various points.

Figure 39. Creating a Unique Key Alternate Index Path for an ESDS
 //OPT9#9    JOB
 //STEP1     EXEC PGM=IDCAMS,REGION=512K
 //SYSPRINT  DD   SYSOUT=A
 //SYSIN     DD   *
    DEFINE ALTERNATEINDEX -
      (NAME(PLIVSAM.AJC1.ALPHIND) -
      VOLUMES(nnnnnn) -
      TRACKS(4 1) -
      KEYS(15 0) -
      RECORDSIZE(20 40) -
      UNIQUEKEY -
     RELATE(PLIVSAM.AJC1.BASE))
 /*
 //STEP2     EXEC PGM=IDCAMS,REGION=512K
 //DD1       DD   DSNAME=PLIVSAM.AJC1.BASE,DISP=SHR
 //DD2       DD   DSNAME=PLIVSAM.AJC1.ALPHIND,DISP=SHR
 //SYSPRINT  DD   SYSOUT=A
 //SYSIN     DD   *
    BLDINDEX  INFILE(DD1)  OUTFILE(DD2)
    DEFINE  PATH -
      (NAME(PLIVSAM.AJC1.ALPHPATH) -
      PATHENTRY(PLIVSAM.AJC1.ALPHIND))
 //
Nonunique Key Alternate Index Path

Figure 40 shows the creation of a nonunique key alternate index path for an ESDS. The alternate index enables the data to be selected by the sex of the children. This enables the girls or the boys to be accessed separately and every member of each group to be accessed by use of the key.

The three Access Method Services commands used are:

DEFINE ALTERNATEINDEX

defines the alternate index as a data set to VSAM.

BLDINDEX

places the pointers to the relevant records in the alternate index.

DEFINE PATH

defines an entity that can be associated with a PL/I file in a DD statement.

DD statements are required for the INFILE and OUTFILE operands of BLDINDEX and for the sort files. Care should be taken that the correct names are specified at the various points.

The fact that the index has nonunique keys is specified by the use of the NONUNIQUEKEY operand. When creating an index with nonunique keys, be careful to ensure that the RECORDSIZE you specify is large enough. In a nonunique alternate index, each alternate index record contains pointers to all the records that have the associated index key. The pointer takes the form of an RBA for an ESDS and the prime key for a KSDS. When a large number of records might have the same key, a large record is required.

Figure 40. Creating a Nonunique Key Alternate Index Path for an ESDS
 //OPT9#10   JOB
 //STEP1     EXEC PGM=IDCAMS,REGION=512K
 //SYSPRINT  DD   SYSOUT=A
 //SYSIN     DD   *
    /* care must be taken with recordsize */
    DEFINE ALTERNATEINDEX -
      (NAME(PLIVSAM.AJC1.SEXIND) -
      VOLUMES(nnnnnn) -
      TRACKS(4 1) -
      KEYS(1 37) -
      RECORDSIZE(20 400) -
      NONUNIQUEKEY -
     RELATE(PLIVSAM.AJC1.BASE))
 /*
 //STEP2     EXEC PGM=IDCAMS,REGION=512K
 //DD1       DD   DSNAME=PLIVSAM.AJC1.BASE,DISP=SHR
 //DD2       DD   DSNAME=PLIVSAM.AJC1.SEXIND,DISP=SHR
 //SYSPRINT  DD   SYSOUT=A
 //SYSIN     DD   *
    BLDINDEX  INFILE(DD1)  OUTFILE(DD2)
    DEFINE  PATH -
      (NAME(PLIVSAM.AJC1.SEXPATH) -
      PATHENTRY(PLIVSAM.AJC1.SEXIND))
 //

Figure 41 shows the creation of a unique key alternate index path for a KSDS. The data set is indexed by the telephone number, enabling the number to be used as a key to discover the name of the person on that extension. The fact that keys are to be unique is specified by UNIQUEKEY. Also, the data set will be able to be listed in numerical order to show which numbers are not used. The three Access Method Services commands used are:

DEFINE ALTERNATEINDEX

defines the data set that will hold the alternate index data.

BLDINDEX

places the pointer to the relevant records in the alternate index.

DEFINE PATH

defines the entity that can be associated with a PL/I file in a DD statement.

DD statements are required for the INFILE and OUTFILE of BLDINDEX and for the sort files. Be careful not to confuse the names involved.

Figure 41. Creating a unique Key Alternate Index Path for a KSDS
 //OPT9#14   JOB
 //STEP1     EXEC PGM=IDCAMS,REGION=512K
 //SYSPRINT  DD   SYSOUT=A
 //SYSIN     DD   *
    DEFINE ALTERNATEINDEX -
      (NAME(PLIVSAM.AJC2.NUMIND) -
      VOLUMES(nnnnnn) -
      TRACKS(4 4) -
      KEYS(3 20) -
      RECORDSIZE(24 48) -
      UNIQUEKEY -
     RELATE(PLIVSAM.AJC2.BASE))
 /*
 //STEP2     EXEC PGM=IDCAMS,REGION=512K
 //DD1       DD   DSNAME=PLIVSAM.AJC2.BASE,DISP=SHR
 //DD2       DD   DSNAME=PLIVSAM.AJC2.NUMIND,DISP=SHR
 //SYSPRINT  DD   SYSOUT=A
 //SYSIN     DD   *
    BLDINDEX  INFILE(DD1)  OUTFILE(DD2)
    DEFINE  PATH -
      (NAME(PLIVSAM.AJC2.NUMPATH) -
      PATHENTRY(PLIVSAM.AJC2.NUMIND))
 //

When creating an alternate index with a unique key, you should ensure that no further records could be included with the same alternate key. In practice, a unique key alternate index would not be entirely satisfactory for a telephone directory as it would not allow two people to have the same number. Similarly, the prime key would prevent one person having two numbers. A solution would be to have an ESDS with two nonunique key alternate indexes, or to restructure the data format to allow more than one number per person and to have a nonunique key alternate index for the numbers.

Detecting Nonunique Alternate Index Keys

If you are accessing a VSAM data set by means of an alternate index path, the presence of nonunique keys can be detected by means of the SAMEKEY built-in function. After each retrieval, SAMEKEY indicates whether any further records exist with the same alternate index key as the record just retrieved. Hence, it is possible to stop at the last of a series of records with nonunique keys without having to read beyond the last record. SAMEKEY (file-reference) returns '1'B if the input/output statement has completed successfully and the accessed record is followed by another with the same key; otherwise, it returns '0'B.

Using Alternate Indexes with ESDSs

Figure 42 shows the use of alternate indexes and backward reading on an ESDS. The program has four files:

BASEFLE

reads the base data set forward.

BACKFLE

reads the base data set backward.

ALPHFLE

is the alphabetic alternate index path indexing the children by name.

SEXFILE

is the alternate index path that corresponds to the sex of the children.

There are DD statements for all the files. They connect BASEFLE and BACKFLE to the base data set by specifying the name of the base data set in the DSNAME parameter, and connect ALPHFLE and SEXFILE by specifying the names of the paths given in Figure 39 and Figure 40.

The program uses SEQUENTIAL files to access the data and print it first in the normal order, then in the reverse order. At the label AGEQUERY, a DIRECT file is used to read the data associated with an alternate index key in the unique alternate index.

Finally, at the label SPRINT, a KEYED SEQUENTIAL file is used to print a list of the females in the family, using the nonunique key alternate index path. The SAMEKEY built-in function is used to read all the records with the same key. The names of the females will be accessed in the order in which they were originally entered. This will happen whether the file is read forward or backward. For a nonunique key path, the BKWD option only affects the order in which the keys are read; the order of items with the same key remains the same as it is when the file is read forward.

Deletion: At the end of the example, the Access Method Services DELETE command is used to delete the base data set. When this is done, the associated alternate indexes and paths will also be deleted.

Using Alternate Indexes with KSDSs

Figure 43 shows the use of a path with a unique alternate index key to update a KSDS and then to access and print it in the order of the alternate index.

The alternate index path is associated with the PL/I file by a DD statement that specifies the name of the path (PLIVSAM.AJC2.NUMPATH, given in the DEFINE PATH command in Figure 41) as the DSNAME.

In the first section of the program, a DIRECT OUTPUT file is used to insert a new record using the alternate index key. Note that any alteration made with an alternate index must not alter the prime key or the alternate index key of access of an existing record. Also, the alternation must not add a duplicate key in the prime index or any unique key alternate index.

In the second section of the program (at the label PRINTIT), the data set is read in the order of the alternate index keys using a SEQUENTIAL INPUT file. It is then printed onto SYSPRINT.

Figure 42. Alternate Index Paths and Backward Reading with an ESDS
   //OPT9#15  JOB
   //STEP1  EXEC IBMZCLG
   //PLI.SYSIN      DD *
     READIT: PROC OPTIONS(MAIN);
       DCL   BASEFLE FILE SEQUENTIAL INPUT ENV(VSAM),
                    /*File to read base data set forward */
             BACKFLE FILE SEQUENTIAL INPUT ENV(VSAM BKWD),
                    /*File to read base data set backward */
             ALPHFLE FILE DIRECT INPUT ENV(VSAM),
             /*File to access via unique alternate index path */
             SEXFILE FILE KEYED SEQUENTIAL INPUT ENV(VSAM),
              /*File to access via nonunique alternate index path */
             STRING CHAR(80),  /*String to be read into */
             1 STRUC DEF (STRING),
               2 NAME CHAR(25),
               2 DATE_OF_BIRTH CHAR(2),
               2 FILL CHAR(10),
               2 SEX CHAR(1);
               DCL NAMEHOLD CHAR(25),SAMEKEY BUILTIN;
               DCL EOF BIT(1) INIT('0'B);

          /*Print out the family eldest first*/

          ON ENDFILE(BASEFLE) EOF='1'B;
          PUT EDIT('FAMILY ELDEST FIRST')(A);
          READ FILE(BASEFLE) INTO (STRING);
          DO WHILE(¬EOF);
             PUT SKIP EDIT(STRING)(A);
             READ FILE(BASEFLE) INTO (STRING);
          END;
          CLOSE FILE(BASEFLE);
          PUT SKIP(2);
           /*Close before using data set from other file not
             necessary but good practice to prevent potential
             problems*/

          EOF='0'B;
          ON ENDFILE(BACKFLE) EOF='1'B;
          PUT SKIP(3) EDIT('FAMILY YOUNGEST FIRST')(A);
          READ FILE(BACKFLE) INTO(STRING);
          DO WHILE(¬EOF);
            PUT SKIP EDIT(STRING)(A);
            READ FILE(BACKFLE) INTO (STRING);
          END;

          CLOSE FILE(BACKFLE);
          PUT SKIP(2);

          /*Print date of birth of child specified in the file
            SYSIN*/
          ON KEY(ALPHFLE) BEGIN;
             PUT SKIP EDIT
                (NAMEHOLD,' NOT A MEMBER OF THE SMITH FAMILY') (A);
             GO TO SPRINT;
          END;
       AGEQUERY:
          EOF='0'B;
          ON ENDFILE(SYSIN) EOF='1'B;
          GET SKIP EDIT(NAMEHOLD)(A(25));
          DO WHILE(¬EOF);
                READ FILE(ALPHFLE) INTO (STRING) KEY(NAMEHOLD);
                PUT SKIP (2) EDIT(NAMEHOLD,' WAS BORN IN ',
                    DATE_OF_BIRTH)(A,X(1),A,X(1),A);
                GET SKIP EDIT(NAMEHOLD)(A(25));
          END;
       SPRINT:
          CLOSE FILE(ALPHFLE);
          PUT SKIP(1);

         /*Use the alternate index to print out all the females in the
           family*/
              ON ENDFILE(SEXFILE) GOTO FINITO;
              PUT SKIP(2) EDIT('ALL THE FEMALES')(A);
              READ FILE(SEXFILE) INTO (STRING) KEY('F');
              PUT SKIP EDIT(STRING)(A);
              DO WHILE(SAMEKEY(SEXFILE));
                 READ FILE(SEXFILE) INTO (STRING);
                 PUT SKIP EDIT(STRING)(A);
              END;

       FINITO:
           END;
      /*
      //GO.BASEFLE   DD   DSN=PLIVSAM.AJC1.BASE,DISP=SHR
      //GO.BACKFLE   DD   DSN=PLIVSAM.AJC1.BASE,DISP=SHR
      //GO.ALPHFLE   DD   DSN=PLIVSAM.AJC1.ALPHPATH,DISP=SHR
      //GO.SEXFILE   DD   DSN=PLIVSAM.AJC1.SEXPATH,DISP=SHR
      //GO.SYSIN     DD    *
      ANDY
      /*
      //STEP2    EXEC PGM=IDCAMS,REGION=512K
      //SYSPRINT    DD    SYSOUT=A
      //SYSIN       DD     *
           DELETE -
                PLIVSAM.AJC1.BASE
      //

Figure 43. Using a Unique Alternate Index Path to Access a KSDS
 //OPT9#16   JOB
 //STEP1     EXEC IBMZCLG,REGION.GO=256K
 //PLI.SYSIN DD   *
    ALTER: PROC OPTIONS(MAIN);
      DCL NUMFLE1 FILE RECORD DIRECT OUTPUT ENV(VSAM),
          NUMFLE2 FILE RECORD SEQUENTIAL INPUT ENV(VSAM),
          IN FILE RECORD,
          STRING CHAR(80),
          NAME CHAR(20) DEF STRING,
          NUMBER CHAR(3) DEF STRING POS(21),
          DATA CHAR(23) DEF STRING,
          EOF BIT(1) INIT('0'B);

      ON KEY (NUMFLE1) BEGIN;
        PUT SKIP EDIT('DUPLICATE NUMBER')(A);
      END;

      ON ENDFILE(IN) EOF='1'B;

      READ FILE(IN) INTO (STRING);
      DO WHILE(¬EOF);
        PUT FILE(SYSPRINT) SKIP EDIT (STRING) (A);
        WRITE FILE(NUMFLE1) FROM (STRING) KEYFROM(NUMBER);
        READ FILE(IN) INTO (STRING);
      END;

      CLOSE FILE(NUMFLE1);

      EOF='0'B;
      ON ENDFILE(NUMFLE2) EOF='1'B;

      READ FILE(NUMFLE2) INTO (STRING);
      DO WHILE(¬EOF);
        PUT SKIP EDIT(DATA)(A);
        READ FILE(NUMFLE2) INTO (STRING);
      END;

      PUT SKIP(3) EDIT('****SO ENDS THE PHONE DIRECTORY****')(A);
   END;
 /*
 //GO.IN    DD   *
 RIERA L            123
 /*
 //NUMFLE1    DD   DSN=PLIVSAM.AJC2.NUMPATH,DISP=OLD
 //NUMFLE2    DD   DSN=PLIVSAM.AJC2.NUMPATH,DISP=OLD
 //STEP2    EXEC PGM=IDCAMS,COND=EVEN
 //SYSPRINT   DD  SYSOUT=A
 //SYSIN   DD    *
      DELETE -
      PLIVSAM.AJC2.BASE
 //

Relative-record data sets

The statements and options allowed for VSAM relative-record data sets (RRDS) are shown in Table 29.

Table 29. Statements and options allowed for loading and accessing VSAM relative-record data sets
File
declaration1
Valid statements, with
options you must include
Other options you can
also include
SEQUENTIAL OUTPUT
BUFFERED
WRITE FILE(file-reference)
FROM(reference);
 
LOCATE based-variable
FILE(file-reference);
KEYFROM(expression) or
KEYTO(reference)
 
SET(pointer-reference)
SEQUENTIAL INPUT
BUFFERED
READ FILE(file-reference)
INTO(reference);
 
READ FILE(file-reference)
SET(pointer-reference);
 
READ FILE(file-reference);2
KEY(expression) or
KEYTO(reference)
 
KEY(expression) or
KEYTO(reference)
 
IGNORE(expression)
SEQUENTIAL UPDATE
BUFFERED
READ FILE(file-reference)
INTO(reference);
 
READ FILE(file-reference)
SET(pointer-reference);
 
READ FILE(file-reference);2
 
WRITE FILE(file-reference)
FROM(reference);
 
REWRITE FILE(file-reference);
 
 
 
DELETE FILE(file-reference);
KEY(expression) or
KEYTO(reference)
 
KEY(expression) or
KEYTO(reference)
 
IGNORE(expression)
 
KEYFROM(expression) or
KEYTO(reference)
 
FROM(reference)
and/or
KEY(expression)
 
KEY(expression)
DIRECT OUTPUT
BUFFERED
WRITE FILE(file-reference)
FROM(reference)
KEYFROM(expression);
 
DIRECT INPUT
BUFFERED
READ FILE(file-reference)
INTO(reference)
KEY(expression);
 
READ FILE(file-reference)
SET(pointer-reference)
KEY(expression);
 
DIRECT UPDATE
BUFFERED
READ FILE(file-reference)
INTO(reference)
KEY(expression);
 
READ FILE(file-reference)
SET(pointer-reference)
KEY(expression);
 
REWRITE FILE(file-reference)
FROM(reference)
KEY(expression);
 
DELETE FILE(file-reference)
KEY(expression);
 
WRITE FILE(file-reference)
FROM(reference)
KEYFROM(expression);
 
Notes:
  1. The complete file declaration would include the attributes FILE and RECORD. If you use any of the options KEY, KEYFROM, or KEYTO, your declaration must also include the attribute KEYED.

    The UNLOCK statement for DIRECT UPDATE files is ignored if you use it for files associated with a VSAM RRDS.

  2. The statement READ FILE(file-reference); is equivalent to the statement READ FILE(file-reference) IGNORE(1);
Loading an RRDS

When an RRDS is being loaded, you must open the associated file for OUTPUT. Use either a DIRECT or a SEQUENTIAL file.

For a DIRECT OUTPUT file, each record is placed in the position specified by the relative record number (or key) in the KEYFROM option of the WRITE statement (see Keys for VSAM data sets).

For a SEQUENTIAL OUTPUT file, use WRITE statements with or without the KEYFROM option. If you specify the KEYFROM option, the record is placed in the specified slot; if you omit it, the record is placed in the slot following the current position. There is no requirement for the records to be presented in ascending relative record number order. If you omit the KEYFROM option, you can obtain the relative record number of the written record by means of the KEYTO option.

If you want to load an RRDS sequentially, without use of the KEYFROM or KEYTO options, your file is not required to have the KEYED attribute.

It is an error to attempt to load a record into a position that already contains a record: if you use the KEYFROM option, the KEY condition is raised; if you omit it, the ERROR condition is raised.

In Figure 44, the data set is defined with a DEFINE CLUSTER command and given the name PLIVSAM.AJC3.BASE. The fact that it is an RRDS is determined by the NUMBERED keyword. In the PL/I program, it is loaded with a DIRECT OUTPUT file and a WRITE...FROM...KEYFROM statement is used.

If the data had been in order and the keys in sequence, it would have been possible to use a SEQUENTIAL file and write into the data set from the start. The records would then have been placed in the next available slot and given the appropriate number. The number of the key for each record could have been returned using the KEYTO option.

The PL/I file is associated with the data set by the DD statement, which uses as the DSNAME the name given in the DEFINE CLUSTER command.

Figure 44. Defining and loading a relative-record data set (RRDS)
 //OPT9#17  JOB
 //STEP1 EXEC PGM=IDCAMS,REGION=512K
 //SYSPRINT DD SYSOUT=A
 //SYSIN    DD *
          DEFINE CLUSTER -
              (NAME(PLIVSAM.AJC3.BASE) -
              VOLUMES(nnnnnn) -
              NUMBERED -
              TRACKS(2 2) -
              RECORDSIZE(20 20))
 /*
 //STEP2  EXEC IBMZCBG
 //PLI.SYSIN      DD *
  CRR1:   PROC OPTIONS(MAIN);
          DCL NOS FILE RECORD OUTPUT DIRECT KEYED ENV(VSAM),
              CARD CHAR(80),
              NAME CHAR(20) DEF CARD,
              NUMBER CHAR(2) DEF CARD POS(21),
              IOFIELD CHAR(20),
              EOF BIT(1) INIT('0'B);
          ON ENDFILE (SYSIN) EOF='1'B;
          OPEN FILE(NOS);
          GET FILE(SYSIN) EDIT(CARD)(A(80));
         DO WHILE (¬EOF);
          PUT FILE(SYSPRINT) SKIP EDIT (CARD) (A);
          IOFIELD=NAME;
          WRITE FILE(NOS) FROM(IOFIELD) KEYFROM(NUMBER);
          GET FILE(SYSIN) EDIT(CARD)(A(80));
          END;
          CLOSE FILE(NOS);
  END CRR1;
 /*
 //GO.NOS DD DSN=PLIVSAM.AJC3.BASE,DISP=OLD
 //GO.SYSIN DD *
 ACTION,G.           12
 BAKER,R.            13
 BRAMLEY,O.H.        28
 CHEESNAME,L.        11
 CORY,G.             36
 ELLIOTT,D.          85
 FIGGINS.E.S.        43
 HARVEY,C.D.W.       25
 HASTINGS,G.M.       31
 KENDALL,J.G.        24
 LANCASTER,W.R.      64
 MILES,R.            23
 NEWMAN,M.W.         40
 PITT,W.H.           55
 ROLF,D.E.           14
 SHEERS,C.D.         21
 SURCLIFFE,M.        42
 TAYLOR,G.C.         47
 WILTON,L.W.         44
 WINSTONE,E.M.       37
 //
Using a SEQUENTIAL file to access an RRDS

You can open a SEQUENTIAL file that is used to access an RRDS with either the INPUT or the UPDATE attribute. If you use any of the options KEY, KEYTO, or KEYFROM, your file must also have the KEYED attribute.

For READ statements without the KEY option, the records are recovered in ascending relative record number order. Any empty slots in the data set are skipped.

If you use the KEY option, the record recovered by a READ statement is the one with the relative record number you specify. Such a READ statement positions the data set at the specified record; subsequent sequential reads will recover the following records in sequence.

WRITE statements with or without the KEYFROM option are allowed for KEYED SEQUENTIAL UPDATE files. You can make insertions anywhere in the data set, regardless of the position of any previous access. For WRITE with the KEYFROM option, the KEY condition is raised if an attempt is made to insert a record with the same relative record number as a record that already exists on the data set. If you omit the KEYFROM option, an attempt is made to write the record in the next slot, relative to the current position. The ERROR condition is raised if this slot is not empty.

You can use the KEYTO option to recover the key of a record that is added by means of a WRITE statement without the KEYFROM option.

REWRITE statements, with or without the KEY option, are allowed for UPDATE files. If you use the KEY option, the record that is rewritten is the record with the relative record number you specify; otherwise, it is the record that was accessed by the previous READ statement.

DELETE statements, with or without the KEY option, can be used to delete records from the dataset.

Using a DIRECT file to access an RRDS

A DIRECT file used to access an RRDS can have the OUTPUT, INPUT, or UPDATE attribute. You can read, write, rewrite, or delete records exactly as though a KEYED SEQUENTIAL file were used.

Figure 45 shows an RRDS being updated. A DIRECT UPDATE file is used and new records are written by key. There is no need to check for the records being empty, because the empty records are not available under VSAM.

In the second half of the program, starting at the label PRINT, the updated file is printed out. Again there is no need to check for the empty records as there is in REGIONAL(1).

The PL/I file is associated with the data sets by a DD statement that specifies the DSNAME PLIVSAM.AJC3.BASE, the name given in the DEFINE CLUSTER command in Figure 45.

At the end of the example, the DELETE command is used to delete the data set.

Figure 45. Updating an RRDS
 //* NOTE: WITH A WRITE STATEMENT AFTER THE DELETE FILE STATEMENT,
 //*       A DUPLICATE MESSAGE IS EXPECTED FOR CODE 'C' ITEMS
 //*       WHOSE NEWNO CORRESPONDS TO AN EXISTING NUMBER IN THE LIST,
 //*       FOR EXAMPLE, ELLIOT.
 //*       WITH A REWRITE STATEMENT AFTER THE DELETE FILE STATEMENT,
 //*       A NOT FOUND MESSAGE IS EXPECTED FOR CODE 'C' ITEMS
 //*       WHOSE NEWNO DOES NOT CORRESPOND TO AN EXISTING NUMBER IN
 //*       THE LIST, FOR EXAMPLE, NEWMAN AND BRAMLEY.
 //OPT9#18  JOB
 //STEP1  EXEC IBMZCBG
 //PLI.SYSIN      DD *
  ACR1:  PROC OPTIONS(MAIN);
                 DCL NOS FILE RECORD KEYED ENV(VSAM),NAME CHAR(20),
                   (NEWNO,OLDNO) CHAR(2),CODE CHAR(1),IOFIELD CHAR(20),
                   BYTE CHAR(1) DEF IOFIELD, EOF BIT(1) INIT('0'B),
                   ONCODE BUILTIN;
         ON ENDFILE(SYSIN) EOF='1'B;
         OPEN FILE(NOS) DIRECT UPDATE;
         ON KEY(NOS) BEGIN;
            IF ONCODE=51 THEN PUT FILE(SYSPRINT) SKIP EDIT
                     ('NOT FOUND:',NAME)(A(15),A);
            IF ONCODE=52 THEN PUT FILE(SYSPRINT) SKIP EDIT
                     ('DUPLICATE:',NAME)(A(15),A);
         END;
         GET FILE(SYSIN) EDIT(NAME,NEWNO,OLDNO,CODE)
            (COLUMN(1),A(20),A(2),A(2),A(1));
         DO WHILE (¬EOF);
         PUT FILE(SYSPRINT) SKIP EDIT (' ',NAME,'#',NEWNO,OLDNO,' ',CODE)
            (A(1),A(20),A(1),2(A(2)),X(5),2(A(1)));
         SELECT(CODE);
            WHEN('A') WRITE FILE(NOS) KEYFROM(NEWNO) FROM(NAME);
            WHEN('C') DO;
             DELETE FILE(NOS) KEY(OLDNO);
             WRITE FILE(NOS) KEYFROM(NEWNO) FROM(NAME);
            END;
            WHEN('D') DELETE FILE(NOS) KEY(OLDNO);
            OTHERWISE PUT FILE(SYSPRINT) SKIP EDIT
              ('INVALID CODE: ',NAME)(A(15),A);
         END;
         GET FILE(SYSIN) EDIT(NAME,NEWNO,OLDNO,CODE)
            (COLUMN(1),A(20),A(2),A(2),A(1));
         END;
          CLOSE FILE(NOS);
             PRINT:
          PUT FILE(SYSPRINT) PAGE;
          OPEN FILE(NOS) SEQUENTIAL INPUT;
          EOF='0'B;
          ON ENDFILE(NOS) EOF='1'B;
           READ FILE(NOS) INTO(IOFIELD) KEYTO(NEWNO);
           DO WHILE (¬EOF);
           PUT FILE(SYSPRINT) SKIP EDIT(NEWNO,IOFIELD)(A(5),A);
           READ FILE(NOS) INTO(IOFIELD) KEYTO(NEWNO);
           END;
        CLOSE FILE(NOS);
  END ACR1;

 /*
 //GO.NOS     DD DSN=PLIVSAM.AJC3.BASE,DISP=OLD
 //GO.SYSIN   DD  *
 NEWMAN,M.W.         5640C
 GOODFELLOW,D.T.     89  A
 MILES,R.              23D
 HARVEY,C.D.W.       29  A
 BARTLETT,S.G.       13  A
 CORY,G.               36D
 READ,K.M.           01  A
 PITT,W.H.             55
 ROLF,D.F.             14D
 ELLIOTT,D.          4285C
 HASTINGS,G.M.         31D
 BRAMLEY,O.H.        4928C
 //STEP3    EXEC PGM=IDCAMS,REGION=512K,COND=EVEN
 //SYSPRINT DD SYSOUT=A
 //SYSIN   DD   *
       DELETE -
           PLIVSAM.AJC3.BASE
 //

Terms of use | Feedback

This information center is powered by Eclipse technology. (http://www.eclipse.org)