Michael Coughlan
Page 54
The next item of note is the change to the READ verb. The direct READ now takes the INVALID KEY clause. This clause allows you to execute some code when an error condition is detected. The sequential read may now use the NEXT RECORD phrase. This phrase is required when ACCESS MODE is DYNAMIC, to indicate that this is a sequential read.
If ACCESS MODE is SEQUENTIAL, then you use the standard READ statement.
Creating a Relative File from a Sequential File
Listing 17-2 shows how to create a relative file from a sequential file. A relative file is a binary file. It can’t be edited in a standard text editor. This makes it a bit awkward to create test data, but most COBOL programming environments have tools that allow you to generate a relative file from a sequential one. Of course, you don’t have to use the tools; you can write a program to do it, as in this example.
Listing 17-2. Creating a Relative File from a Sequential File
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing17-2.
AUTHOR. MICHAEL COUGHLAN.
* Reads a Relative file directly or in sequence
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT VehicleFile ASSIGN TO "Listing17-2.DAT"
ORGANIZATION IS RELATIVE
ACCESS MODE IS RANDOM
RELATIVE KEY IS VehicleKey
FILE STATUS IS VehicleStatus.
SELECT Seqfile ASSIGN TO "Listing17-2.SEQ"
ORGANIZATION IS LINE SEQUENTIAL.
439
Chapter 17 ■ DireCt aCCess Files
DATA DIVISION.
FILE SECTION.
FD VehicleFile.
01 VehicleRec.
02 VehicleNum PIC 9(4).
02 VehicleDesc PIC X(25).
02 ManfName PIC X(20).
FD SeqFile.
01 VehicleRec-SF.
88 EndOfSeqfile VALUE HIGH-VALUES.
02 VehicleNum-SF PIC 9(4).
02 VehicleDesc-SF PIC X(25).
02 ManfName-SF PIC X(20).
WORKING-STORAGE SECTION.
01 VehicleStatus PIC X(2).
88 RecordFound VALUE "00".
01 VehicleKey PIC 9(4).
PROCEDURE DIVISION.
BEGIN.
OPEN INPUT SeqFile
OPEN OUTPUT VehicleFile
READ SeqFile
AT END SET EndOfSeqFile TO TRUE
END-READ
PERFORM UNTIL EndOfSeqFile
MOVE VehicleNum-SF TO VehicleKey
WRITE VehicleRec FROM VehicleRec-SF
INVALID KEY DISPLAY "Vehicle file status = " VehicleStatus
END-WRITE
READ SeqFile
AT END SET EndOfSeqFile TO TRUE
END-READ
END-PERFORM
CLOSE SeqFile, VehicleFile
STOP RUN.
In this program, the first thing to note is that because the relative file only uses direct access, the ACCESS MODE
specified is RANDOM.
The relative file is created as follows. For each record in the sequential file, the program reads the record, moves the contents of the VehicleNum field to the relative key VehicleKey, and then writes the relative record from the sequential record. The record is written into the position indicated by the relative record number in VehicleKey.
440
Chapter 17 ■ DireCt aCCess Files
Applying Transactions to a Relative File
In this final example program (see Listing 17-3), you see how to apply a sequential file of transactions to the relative vehicle master file. The transaction file contains only enough transactions to demonstrate valid and invalid insertions, valid and invalid updates (VehicleDesc is updated), and valid and invalid deletions. To keep the program short, it uses displays to report transaction errors. To make the updates clear, the contents of the vehicle master file are displayed before and after the transactions are applied. The contents of the transaction file are shown in Example 17-1.
Example 17-1. Contents of the Transaction File
I0001 *** invalid insert *** Tesla Motors
D0006 *** invalid delete ***
U0017FCV +valid update
U0117 *** invalid update ***
D0135 +valid delete
I0205Model C +valid insert Tesla Motors
I0230 *** invalid insert *** Peugeot
Listing 17-3. Applying a Sequential File of Transactions to a Relative File
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing17-3.
AUTHOR. MICHAEL COUGHLAN.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT VehicleMasterFile ASSIGN TO "Listing17-3.DAT"
ORGANIZATION IS RELATIVE
ACCESS MODE IS DYNAMIC
RELATIVE KEY IS VehicleKey
FILE STATUS IS VehicleFileStatus.
SELECT TransFile ASSIGN TO "Listing17-3Trans.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD VehicleMasterFile.
01 VehicleRec-VMF.
88 EndOfVehiclefile VALUE HIGH-VALUES.
02 VehicleNum-VMF PIC 9(4).
02 VehicleDesc-VMF PIC X(25).
02 ManfName-VMF PIC X(20).
441
Chapter 17 ■ DireCt aCCess Files
FD TransFile.
01 InsertionRec.
88 EndOfTransFile VALUE HIGH-VALUES.
02 TransType PIC X.
88 InsertRecord VALUE "I".
88 DeleteRecord VALUE "D".
88 UpdateRecord VALUE "U".
02 VehicleNum-IR PIC 9(4).
02 VehicleDesc-IR PIC X(25).
02 ManfName-IR PIC X(20).
01 DeletionRec PIC X(5).
01 UpdateRec.
02 FILLER PIC X(5).
02 VehicleDesc-UR PIC X(25).
WORKING-STORAGE SECTION.
01 VehicleFileStatus PIC X(2).
88 OperationSuccessful VALUE "00".
88 VehicleRecExists VALUE "22".
88 NoVehicleRec VALUE "23".
01 VehicleKey PIC 9(4).
01 ReadType PIC 9.
PROCEDURE DIVISION.
Begin.
OPEN INPUT TransFile
OPEN I-O VehicleMasterFile
DISPLAY "Vehicle Master File records before transactions"
PERFORM DisplayVehicleRecords
DISPLAY SPACES
READ TransFile
AT END SET EndOfTransFile TO TRUE
END-READ
PERFORM UNTIL EndOfTransFile
MOVE VehicleNum-IR TO VehicleKey
EVALUATE TRUE
WHEN InsertRecord PERFORM InsertVehicleRec
WHEN DeleteRecord PERFORM DeleteVehicleRec
WHEN UpdateRecord PERFORM UpdateVehicleRec
WHEN OTHER DISPLAY "Error - Invalid Transaction Code"
END-EVALUATE
READ TransFile
AT END SET EndOfTransFile TO TRUE
END-READ
END-PERFORM
442
Chapter 17 ■ DireCt aCCess Files
DISPLAY SPACES
DISPLAY "Vehicle Master File records after transactions"
PERFORM DisplayVehicleRecords
CLOSE TransFile, VehicleMasterFile
STOP RUN.
InsertVehicleRec.
MOVE ManfName-IR TO ManfName-VMF
MOVE VehicleDesc-IR TO VehicleDesc-VMF
MOVE VehicleNum-IR TO VehicleNum-VMF
WRITE VehicleRec-VMF
INVALID KEY
IF VehicleRecExists
DISPLAY "InsertError - Record at - " VehicleNum-IR " - already exists"
ELSE
DISPLAY "Unexpected error. File Status is - " VehicleFileStatus
END-IF
END-WRITE.
DeleteVehicleRec.
DELETE VehicleMasterFile RECORD
INVALID KEY
IF NoVehicleRec
DISPLAY "DeleteError - No record at - " VehicleNum-IR
ELSE
DISPLAY "Unexpected error1. File Status is - " VehicleFileStatus
END-IF
END-DELETE.
UpdateVehicleRec.
READ VehicleMasterFile
INVALID KEY
IF NoVehicleRec
DISPLAY "UpdateError - No record at - " VehicleNum-IR
ELSE
DISPLAY "Unexpected error2. File Status is - " VehicleFileStatus
END-IF
END-READ
IF OperationSuccessful
MOVE VehicleDesc-UR TO VehicleDesc-VMF
REWRITE VehicleRec-VMF
INVALID KEY DISPLAY "Unexpected error3. File Status is - " VehicleFileStatus
END-REWRITE
END-IF.
DisplayVehicleRecords.
* Position the Next Record Pointer to the start of the file
MOVE ZEROS TO VehicleKey
START VehicleMasterFile KEY IS GREATER THAN VehicleKey
443
Chapter 17 ■ DireCt aCCess Files
INVALID KEY DISPLAY "Unexpected error on START"
END-START
READ VehicleMasterFile NEXT RECORD
AT END SET EndOfVehiclefile TO TRUE
END-READ
PERFORM UNTIL EndOfVehiclefile
DISPLAY VehicleNum-VMF SPACE VehicleDesc-VMF SPACE ManfName-VMF
READ VehicleMasterFile NEXT RECORD
AT END SET EndOfVehiclefile TO TRUE
END-READ
END-PERFORM.
The most interesting thing about this program is that it uses all five of the direct access file processing verbs: READ, WRITE, REWRITE, DELETE, and START. The program begins by displaying the current contents of the vehicle master file.
You may wonder what the purpose of the START verb is at the beginning of DisplayVehicleRecords. For relative files, the START verb is used to position the next-record pointer. When a file is accessed sequentially, the next-record pointer points to the position in the file where the next record will be read from or written to.
This first time through DisplayVehicleRecords, the START verb is not strictly necessary, because when you open the file, the next-record pointer points to the first record in the file by default. But the second time through the file, the START
verb is required in order to position the next-record pointer at the beginning of the file—when you read through the file the first time, the next-record pointer was left pointing to the last record in the file. Closing the file and opening it again also positions the next-record pointer at the first record in the file, but doing so carries a significant processing penalty.
Note how you use the START verb. You move zeros into the relative-key data item; then, when START executes, its meaning is this: position the next-record pointer such that the relative record number of the record pointed to is greater than the current value of the relative-key data item. Because the current value of the relative-key data item is zero, the first valid record in the file satisfies the condition.
The first statement in the PERFORM UNTIL EndOfTransFile iteration is MOVE VehicleNum-IR TO VehicleKey.
This takes the key value in the transaction record and places it in the relative-key data item. Now any direct access operation such as WRITE, REWRITE, or DELETE will use that key value.
If the transaction is an insertion, then a direct WRITE is used to write the transaction record to the vehicle master file at the relative record number indicated by the value in VehicleKey. If the WRITE fails, then INVALID KEY activates, and the file status is checked to see if it has failed because there is already a record in that relative record number position or because of an unexpected error. If the anticipated error condition occurs, an error message is displayed, indicating the offending record’s key value; otherwise, an error message and the current value of the file status are displayed. The second part of the IF statement is there as an alert regarding a possible programming or test data error; you don’t expect this branch of IF to be triggered.
If the transaction is a deletion, then the direct DELETE is used to delete the record at the relative record number position pointed to by the value in VehicleKey. If there is no record at that position, INVALID KEY activates.
If the transaction is an update, then a direct READ is used to fetch the record from the file and place it in the record buffer. If the record exists, the VehicleDesc-VMF field is updated, and REWRITE is used to write the record back to the file. REWRITE has to be used because WRITE would return an error if it found a record already in place.
Relative Files: Syntax and Semantics
This section provides a formal introduction to the file-processing verbs and declarations specific to relative files.
Relative Files: SELECT and ASSIGN Clause
The metalanguage for the SELECT and ASSIGN clause for relative files is shown in Figure 17-2.
444
Chapter 17 ■ DireCt aCCess Files
Figure 17-2. Metalanguage for the specific relative SELECT and ASSIGN clause
Normally, when a file is opened for INPUT, I-O, or EXTEND, the file must exist or an error condition occurs. The OPTIONAL phrase allows you to specify that the file does not have to exist (presumably because you are going to write records to and read records from it) when OPEN INPUT, OPEN I-O, or OPEN EXTEND executes.
ACCESS MODE refers to the way in which the file is to be used. If you specify that ACCESS MODE is SEQUENTIAL, then it is only possible to process the records in the file sequentially. If RANDOM is specified, it is only possible to access the file directly. If DYNAMIC is specified, the file may be accessed both directly and sequentially.
The RECORD KEY phrase is used to define the relative key. There can be only one key in a relative file. RelKey must be a numeric data item and must not be part of the file’s record description, although it may be part of another file’s record description. It is normally described in the WORKING-STORAGE SECTION.
The FILE STATUS clause identifies a two-character area of storage that holds the result of every I/O operation for the file. The FILE STATUS data item is declared as PIC X(2) in the WORKING-STORAGE SECTION. Whenever an I/O
operation is performed, some value is returned to FILE STATUS, indicating whether the operation was successful.
There are a large number of FILE STATUS values, but three of major interest for relative files are as follows:
• "00" means the operation was successful.
• "22" indicates a duplicate key. That is, you are trying to write a record, but a record already exists in that position.
• "23" means the record was not found. That is, you are trying to access a record, but there is no record in that position.
Relative File Verbs
Direct access files are more versatile than sequential files and support a greater range of operations. In addition to the new file-processing verbs DELETE, REWRITE, and START, many of the verbs you already know—such as OPEN, CLOSE, READ, and WRITE—operate differently when processing direct access files.
INVALID KEY Clause
If you examine the metalanguage of any of the direct access verbs, you see that the INVALID KEY clause is in square brackets, indicating that this clause is optional. In reality, the INVALID KEY clause is mandatory unless declaratives have been specified. Declaratives allow you to create specialized exception-handling code. You explore declaratives in the next chapter.
When the INVALID KEY clause is specified, any I/O error, such as attempting to read or delete a record that does not exist or write a record that already exists, activates the clause and causes the statement block following it to be executed.
445
Chapter 17 ■ DireCt aCCess Files
OPEN/CLOSE
The CLOSE syntax is the same for all file organizations.
The syntax for OPEN changes when used with direct access files: an I-
O (input/output) entry is added. I-O is used with direct access files when you intend to update or both read from and write to the file. The full metalanguage for the OPEN verb is given in Figure 17-3.
Figure 17-3. Full metalanguage for the OPEN verb
Consider the following:
• If the file is opened for INPUT, then only READ and START are allowed.
• If the file is opened for OUTPUT, then only WRITE is allowed.
• If the file is opened for I-O, then READ, WRITE, START, REWRITE, and DELETE are allowed.
• If OPEN INPUT is used, and the file does not possess the OPTIONAL clause, the file must exist or
the OPEN will fail.
• If OPEN OUTPUT or I-O is used, the file will be created if it does not already exist, as long as the
file possesses the OPTIONAL clause.
READ Verb
There are two new formats for the READ verb. One format is used for a direct READ on a relative file, and the other is used when you want to read the file sequentially but an ACCESS MODE of DYNAMIC has been specified for the file. When an ACCESS MODE of SEQUENTIAL is specified, all file organizations use the standard READ format.
The metalanguage in Figure 17-4 shows the READ format used to read a relative file sequentially when an ACCESS
MODE of DYNAMIC has been specified. The only difference between this format and the format of the ordinary sequential READ is the NEXT RECORD phrase. This format of READ reads the record pointed to by the next-record pointer (the current record if positioned by START, or the next record if positioned by a direct READ).
Figure 17-4. Metalanguage for the sequential READ when the ACCESS MODE is DYNAMIC
The format of READ used for a direct read on a relative file is shown in Figure 17-5. To read a relative file using a key, the relative record number of the required record is placed in the RELATIVE KEY data item (specified in the RELATIVE KEY phrase of the file’s SELECT and ASSIGN clause), and then READ is executed. When READ executes, the record with the relative record number equal to the present value of the relative key is read into the file’s record buffer (defined in the FD entry). If READ fails to retrieve the record, the INVALID KEY activates, and the statement block following the clause is executed. If READ is successful, NOT INVALID KEY (if present) activates, and the next-record pointer is left pointing to the next valid record in the file.