Michael Coughlan
Page 55
446
Chapter 17 ■ DireCt aCCess Files
Figure 17-5. Metalanguage for the direct READ
WRITE Verb
The format for writing sequentially to a direct access file is the same as that used for writing to a sequential file. But when you want to write directly to a relative file, a key must be used, and this requires the WRITE format shown in Figure 17-6.
Figure 17-6. Metalanguage for writing to a relative file using a key
Writing a record to a relative file using a key requires you to place the record in the record buffer, place the key value in the RELATIVE KEY data item, and then execute the WRITE statement. When WRITE executes, the data in the record buffer is written to the record position with a relative record number equal to the present value of the key.
If WRITE fails, perhaps because a record already exists at that relative record number position, the INVALID KEY
clause activates, and the statements following the clause are executed.
REWRITE Verb
The REWRITE verb is used to update a record in situ by overwriting it. The format of REWRITE is given in Figure 17-7. The REWRITE verb is generally used with READ because you can only update a record by bringing it into the record buffer first. Once the record is in the buffer, you can make the changes to the required fields; when the changes have been made, you REWRITE the record to the file.
Figure 17-7. Metalanguage for the REWRITE verb
To use REWRITE to update fields in a record, you first place the key value in the RELATIVE KEY data item and do a direct READ. This brings the required record into the record buffer. Next you make the required changes to the data in the record. Then you execute a REWRITE to write the record in the buffer back to the file.
Keep the following in mind:
• If the file has an ACCESS MODE of SEQUENTIAL, then the INVALID KEY clause cannot be specified,
and the record to be replaced must have been the subject of a READ or START before the
REWRITE is executed.
• For all access modes, the file must be opened for I-O.
447
Chapter 17 ■ DireCt aCCess Files
DELETE Verb
The syntax for the DELETE verb is given in Figure 17-8. To delete a record, you place the key value in the RELATIVE KEY
data item and then execute DELETE. The record in the relative record number position indicated by the RELATIVE KEY
data item is marked as deleted (it is not actually deleted). If the DELETE attempt fails, perhaps because there is no record at that position, INVALID KEY activates.
Figure 17-8. Metalanguage for the DELETE verb
Note the following:
• To use DELETE, the file must have been opened for I-O.
• When ACCESS MODE is SEQUENTIAL, a READ statement must have accessed the record to be
deleted (that’s how the system knows which record to delete).
START Verb
For relative files, the START verb is only used to control the position of the next-record pointer. Where the START verb appears in a program, it is usually followed by a sequential READ or WRITE because START does not get data from or put data into the file. It merely positions the next-record pointer.
To use the START verb to position the next-record pointer at a particular record (so that subsequent sequential accesses will use that record position), you place the key value of the record at the desired position into the RELATIVE
KEY data item and then execute a START..KEY IS EQUAL TO statement.
To use the START verb to position the next-record pointer at the first active record in the file, you move zeros to the RELATIVE KEY data item and then execute a START..KEY IS GREATER THAN statement. You can’t move the number 1
to the RELATIVE KEY data item, because there may be no active record in the first record position.
The metalanguage for the START verb is given in Figure 17-9. When START executes, it has the following interpretation: position the next-record pointer such that the relative record number of the record pointed to is EQUAL
TO or GREATER THAN or NOT LESS THAN or GREATER THAN OR EQUAL TO the current value of the RELATIVE KEY data item.
Figure 17-9. Metalanguage for the START verb
448
Chapter 17 ■ DireCt aCCess Files
Organization of Indexed Files
Unlike relative files, which only allow a single, numeric key, an indexed file may have up to 255 alphanumeric keys.
The key on which the data records are actually ordered is called the primary key. The other keys are called alternate keys. Although a relative file allows you to access records sequentially or directly by key, an indexed file lets you access the records directly or sequentially using any of its keys. For instance, suppose an indexed file supporting a video rental system has VideoId as its primary key and VideoTitle and SupplierId as its alternate keys. You can read a record from the file using any of the keys, and you can also read through the file in VideoId sequence, VideoTitle sequence, or SupplierId sequence. This versatility is what makes indexed files so useful.
How is this flexibility achieved? How can it be possible to read through the file sequentially in different sequences?
The data records in an indexed file are sequenced in ascending primary-key order. Over the data records, the file system builds an index. This arrangement is shown schematically in Figure 17-10.
Figure 17-10. Primary-key index: seeking a record with a key value of 43
A number of terms relating to Figure 17-10 need clarification. A bucket is the smallest number of characters of disk storage that can be read or written in one I/O operation. It is the equivalent of a block on a PC disk—the smallest segment of disk space that can be addressed. Index depth is the number of levels of index above level 0, which is the data bucket (or base bucket) level (in Figure 17-10, the index depth is 2).
When direct access is required, the file system uses the index to find, read, insert, update, or delete the required record. Figure 17-11 shows how the index is used to locate the record with a key value of 43. The file system starts at the first level of index (one I/O operation is required to bring the records in this bucket into memory). In the index buckets, each index record contains a pointer to the highest key value in the next-level buckets. Using the condition IF
SeekVal <= IndexKeyVal, a bucket is retrieved from the next level of index (another I/O operation is required to bring the records in this bucket into memory). Again the condition is applied, and the bucket at level 0 (the data buckets) is retrieved (another final I/O is required to bring the records in this bucket into memory). Once the actual data records are in memory, the file system searches them sequentially until the required record is found.
449
Chapter 17 ■ DireCt aCCess Files
Figure 17-11. Alternate-key index: seeking a record with a key value of Vt
In addition to allowing direct access to records on the primary key or any of the 254 alternate keys, indexed files may also be processed sequentially. When you process an indexed file sequentially, you can read the records in ascending order on the primary key or on any of the alternate keys.
Because the data records are held in ascending primary-key sequence, it is easy to see how the file may be accessed sequentially on the primary key. It is not quite so obvious how you achieve sequential access on the alternate keys. For this, you need to examine the alternate index schematic in Figure 17-11.
For each of the alternate keys specified in an indexed file, an alternate index is built. However, unlike the primary-key index, which contains the data buckets at the lowest level of the index, the lowest level of an alternate index is made up of base records that contain only the alternate-key value and a pointer to where the actual record is.
These base records are organized in ascending alternate-key order; by reading though these base records in sequence, you achieve sequential access using the alternate key. Th
is arrangement is shown schematically in Figure 17-11.
Figure 17-11 shows how the index is used to locate the record with a key value of Vt. As with the primary key, each level of index points to the next level until level 0 is reached. Each of the base buckets at level 0 contains records that consist of the alternate-key value and a pointer to the data bucket where the record with that key value is to be found.
In Figure 17-11, for example, the Vt record in the base buckets points to a bucket that actually contains the record.
Note that the records in this bucket are in ascending primary key order.
Processing Indexed Files
Just as with relative files, this section introduces indexed files by showing you some simple examples. When you have a feel for how it all works, you learn about the required clauses, verbs, and concepts more formally.
Let’s start with a simple program that reads an indexed file both sequentially and directly on a number of keys.
Then you see how to create an indexed file from a sequential file. In the third example, you learn how to use indexed files in combination: you use an indexed file of film directors and an indexed file containing film details together to display all the films directed by a particular director. In the final example, you apply a set of transactions to the film file and cover the issue of referential integrity that crops up when a new film record is inserted.
450
Chapter 17 ■ DireCt aCCess Files
Reading an Indexed File
Listing 17-4 displays the contents of an indexed file in the key sequence chosen by the user and then displays one record directly using the key chosen by the user.
Listing 17-4. Reading an indexed file sequentially and then directly using any key
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing17-4.
AUTHOR. Michael Coughlan.
*Reads the file sequentially and then directly on any key
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
SELECT FilmFile ASSIGN TO "Listing17-4Film.DAT"
ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS FilmId
ALTERNATE RECORD KEY IS FilmTitle
WITH DUPLICATES
ALTERNATE RECORD KEY IS DirectorId
WITH DUPLICATES
FILE STATUS IS FilmStatus.
DATA DIVISION.
FILE SECTION.
FD FilmFile.
01 FilmRec.
88 EndOfFilms VALUE HIGH-VALUES.
02 FilmId PIC 9(7).
02 FilmTitle PIC X(40).
02 DirectorId PIC 999.
WORKING-STORAGE SECTION.
01 FilmStatus PIC XX.
88 FilmOK VALUE ZEROS.
01 RequiredSequence PIC 9.
88 FilmIdSequence VALUE 1.
88 FilmTitleSequence VALUE 2.
88 DirectorIdSequence VALUE 3.
PROCEDURE DIVISION.
Begin.
OPEN INPUT FilmFile
DISPLAY "*** Get Records Sequentially ***"
DISPLAY "Enter key : 1 = FilmId, 2 = FilmTitle, 3 = DirectorId - "
WITH NO ADVANCING.
ACCEPT RequiredSequence.
EVALUATE TRUE
WHEN FilmIdSequence PERFORM DisplayFilmData
451
Chapter 17 ■ DireCt aCCess Files
WHEN FilmTitleSequence MOVE SPACES TO FilmTitle
START FilmFile KEY IS GREATER THAN FilmTitle
INVALID KEY DISPLAY "FilmStatus = " FilmStatus
END-START
PERFORM DisplayFilmData
WHEN DirectorIdSequence MOVE ZEROS TO DirectorId
START FilmFile KEY IS GREATER THAN DirectorId
INVALID KEY DISPLAY "FilmStatus = " FilmStatus
END-START
PERFORM DisplayFilmData
END-EVALUATE
DISPLAY SPACES
DISPLAY "*** Get Records Directly ***"
DISPLAY "Enter key : 1 = FilmId, 2 = FilmTitle, 3 = DirectorId - "
WITH NO ADVANCING.
ACCEPT RequiredSequence.
EVALUATE TRUE
WHEN FilmIdSequence PERFORM GetFilmByFilmId
WHEN FilmTitleSequence PERFORM GetFilmByFilmTitle
WHEN DirectorIdSequence PERFORM GetFilmByDirectorId
END-EVALUATE
CLOSE FilmFile
STOP RUN.
DisplayFilmData.
READ FilmFile NEXT RECORD
AT END SET EndOfFilms TO TRUE
END-READ
PERFORM UNTIL EndOfFilms
DISPLAY FilmId SPACE FilmTitle SPACE DirectorId
READ FilmFile NEXT RECORD
AT END SET EndOfFilms TO TRUE
END-READ
END-PERFORM.
GetFilmByFilmId.
DISPLAY "Enter the FilmId - " WITH NO ADVANCING
ACCEPT FilmId
READ FilmFile
KEY IS FilmId
INVALID KEY DISPLAY "Film not found - " FilmStatus
NOT INVALID KEY DISPLAY FilmId SPACE FilmTitle SPACE DirectorId
END-READ.
GetFilmByFilmTitle.
DISPLAY "Enter the FilmTitle - " WITH NO ADVANCING
ACCEPT FilmTitle
452
Chapter 17 ■ DireCt aCCess Files
READ FilmFile
KEY IS FilmTitle
INVALID KEY DISPLAY "Film not found - " FilmStatus
NOT INVALID KEY DISPLAY FilmId SPACE FilmTitle SPACE DirectorId
END-READ.
GetFilmByDirectorId.
DISPLAY "Enter the Director Id - " WITH NO ADVANCING
ACCEPT DirectorId
READ FilmFile
KEY IS DirectorId
INVALID KEY DISPLAY "Film not found - " FilmStatus
NOT INVALID KEY DISPLAY FilmId SPACE FilmTitle SPACE DirectorId
END-READ.
There is quite a bit to talk about in this program. The first thing to note is the new entries in the SELECT and ASSIGN
clause. Because an indexed file has a primary key and, perhaps, some alternate keys, you must have entries in SELECT
and ASSIGN for each key, and you must distinguish the primary key from the alternate keys. One very important thing to remember is that whereas the key defined in the RELATIVE KEY entry of a relative file cannot be a field in the relative file’s record description, the keys defined for an indexed file must be fields in the record defined for the file.
Another item of interest is the WITH DUPLICATES phrase, which is specified with the ALTERNATE KEY clause in the SELECT and ASSIGN clause. In a relative file, the key must be unique; and in an indexed file, the primary key defined in the RECORD KEY clause must be unique, but the alternate keys may have duplicates if they use the WITH DUPLICATES
phrase. For instance, in this program, the same DirectorId appears for many films. If the WITH DUPLICATES phrase is omitted, the alternate key has to be unique.
453
Chapter 17 ■ DireCt aCCess Files
The program starts by asking the user what key to use when displaying the contents of the file sequentially. This raises an interesting question. If you examine the code in the paragraph DisplayFilmData, you see that the READ
format used is the one for reading a file sequentially. So the question is, how does the system know to read through the file in FilmId order on one occasion, in FilmTitle order on another occasion, and in DirectorId order on yet another occasion? The answer is that the system relies on a concept called the key of reference. The key of reference refers to the key that is used to process an indexed file sequentially. A particular key is established as the key of reference by using that key with START or a direct READ. You can see this in the program. If FilmTitleSequence is selected, START is used with the FilmTitle key to both establish FilmTitle as the key of reference and position the next-record pointer at the first record. Similarly, if DirectorIdSequence is selected, START is used to establish Direc
torId as the key of reference and to position the next-record pointer at the first record in the file. What about FilmIdSequence, though?
Why doesn’t that WHEN branch have a START verb? I could have used START with that branch, too, but I wanted to make the point that when the file is opened, the primary key is the default key of reference and the next-record pointer is pointing at the first record in the file.
When the program has displayed the contents of the file in the required sequence, the user is asked which key they wish to use for a direct READ. Then that key is used to read the required record from the file. If you examine the READ operation in any of the paragraphs that read the record from the file, you see that this format of READ is different from that used for relative files. For relative files, READ does not require a KEY IS phrase because there is only one key; but because indexed files use many keys, you have to say which key you are using to read the record.
One final issue needs to be discussed. The paragraph GetFilmByDirectorId returns only one record, but the
same director occurs many times in the file. How can you show the other films made by this director? The answer lies once more in the key of reference. When a direct READ is made, the key used is established as the key of reference, and the next-record pointer is pointing at the next record in the file. You can display all the films made by a particular director by doing a direct READ followed by sequential READs. You stop reading the records when the Director Id changes. This procedure is shown in the revised version of GetFilmByDirectorId in Example 17-2.