Virgo
Earth
08-25
09-22
9
Libra
Air
09-25
10-22
10
Scorpio
Water
10-25
11-21
11
Sagittarius Fire
11-24
12-20
12
Capricorn Earth
12-23
01-19
13
Cusp
Cusp
Cusp
Cusp
Processing
Write a contained subprogram called IdentifySign to identify the Zodiac sign for a given birth date. the
IdentifySign subprogram should take DateOfBirth as an input parameter and should return SignCode
(shown in the previous table) as its return/output parameter. a code of 13 should be returned for cusp births.
For each record in the file, do the following:
• increment the TotalRecords count.
• Call IdentifySign to get ZodiacSign for MaleDOB.
• Call IdentifySign to get ZodiacSign for FemaleDOB.
if either spouse had a cusp birth, then ignore the record. Otherwise, if the signs are compatible, increment the CompatiblePairs count; and if they are incompatible, increment the IncompatiblePairs count.
430
Chapter 16 ■ Creating Large SyStemS
prOGraMMING eXerCISe: aNSWer
Listing 16-9. Zodiac Sign Compatibility Tester
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing16-9.
AUTHOR. Michael Coughlan.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT BirthsFile ASSIGN TO "Listing16-9MPDOB.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD BirthsFile.
01 BirthsRec.
88 EndOfFile VALUE HIGH-VALUES.
02 MaleDOB PIC X(8).
02 FemaleDOB PIC X(8).
WORKING-STORAGE SECTION.
01 Counts.
02 CompatiblePairs PIC 9(7) VALUE ZEROS.
02 CompatiblePrn PIC ZZZZ,ZZ9.
02 CompatiblePercent PIC ZZ9.
02 IncompatiblePairs PIC 9(7) VALUE ZEROS.
02 IncompatiblePrn PIC ZZZZ,ZZ9.
02 IncompatiblePercent PIC ZZ9.
02 ValidRecs PIC 9(8) VALUE ZEROS.
02 ValidRecsPrn PIC ZZ,ZZZ,ZZ9.
02 TotalRecs PIC 9(9) VALUE ZEROS.
02 TotalRecsPrn PIC ZZ,ZZZ,ZZ9.
01 MaleSignType PIC 99.
88 ValidMale VALUE 1 THRU 12.
01 FemaleSignType PIC 99.
88 ValidFemale VALUE 1 THRU 12.
01 SumOfSigns PIC 99.
PROCEDURE DIVISION.
Begin.
OPEN INPUT BirthsFile.
READ BirthsFile
AT END SET EndOfFile TO TRUE
END-READ
PERFORM ProcessBirthRecs UNTIL EndOfFile
431
Chapter 16 ■ Creating Large SyStemS
COMPUTE ValidRecs = CompatiblePairs + IncompatiblePairs
COMPUTE CompatiblePercent ROUNDED = CompatiblePairs / ValidRecs * 100
COMPUTE InCompatiblePercent ROUNDED = InCompatiblePairs / ValidRecs * 100
PERFORM DisplayResults
CLOSE BirthsFile.
STOP RUN.
DisplayResults.
MOVE CompatiblePairs TO CompatiblePrn
MOVE IncompatiblePairs TO IncompatiblePrn
MOVE TotalRecs TO TotalRecsPrn
MOVE ValidRecs TO ValidRecsPrn
DISPLAY "Total records = " TotalRecsPrn
DISPLAY "Valid records = " ValidRecsPrn
DISPLAY "Compatible pairs = " CompatiblePrn
" which is " CompatiblePercent "% of total".
DISPLAY "Incompatible pairs = " IncompatiblePrn
" which is " InCompatiblePercent "% of total".
ProcessBirthRecs.
* Get the two sign types and add them together
* If the result is even then they are compatible
ADD 1 TO TotalRecs
CALL "IdentifySign" USING BY CONTENT MaleDOB
BY REFERENCE MaleSignType
CALL "IdentifySign" USING BY CONTENT FemaleDOB
BY REFERENCE FemaleSignType
IF ValidMale AND ValidFemale
COMPUTE SumOfSigns = MaleSignType + FemaleSignType
IF FUNCTION REM(SumOfSigns 2) = ZERO
ADD 1 TO CompatiblePairs
ELSE
ADD 1 TO IncompatiblePairs
END-IF
END-IF
READ BirthsFile
AT END SET EndOfFile TO TRUE
END-READ.
IDENTIFICATION DIVISION.
PROGRAM-ID. IdentifySign IS INITIAL.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WorkDate.
88 Aquarius VALUE "0122" THRU "0218".
88 Pisces VALUE "0221" THRU "0319".
88 Aries VALUE "0322" THRU "0419".
432
Chapter 16 ■ Creating Large SyStemS
88 Taurus VALUE "0422" THRU "0520".
88 Gemini VALUE "0523" THRU "0620".
88 Cancer VALUE "0623" THRU "0722".
88 Leo VALUE "0725" THRU "0822".
88 Virgo VALUE "0825" THRU "0922".
88 Libra VALUE "0925" THRU "1022".
88 Scorpio VALUE "1025" THRU "1121".
88 Sagittarius VALUE "1124" THRU "1220".
88 Capricorn VALUE "1223" THRU "1231", "0101" THRU "0119".
02 WorkMonth PIC XX.
02 WorkDay PIC XX.
LINKAGE SECTION.
01 DateOfBirth.
02 BirthMonth PIC XX.
02 BirthDay PIC XX.
02 FILLER PIC 9(4).
01 SignType PIC 99.
PROCEDURE DIVISION USING DateOfBirth, SignType.
Begin.
MOVE BirthDay TO WorkDay.
MOVE BirthMonth TO WorkMonth.
EVALUATE TRUE
WHEN Aquarius MOVE 1 TO SignType
WHEN Pisces MOVE 2 TO SignType
WHEN Aries MOVE 3 TO SignType
WHEN Taurus MOVE 4 TO SignType
WHEN Gemini MOVE 5 TO SignType
WHEN Cancer MOVE 6 TO SignType
WHEN Leo MOVE 7 TO SignType
WHEN Virgo MOVE 8 TO SignType
WHEN Libra MOVE 9 TO SignType
WHEN Scorpio MOVE 10 TO SignType
WHEN Sagittarius MOVE 11 TO SignType
WHEN Capricorn MOVE 12 TO SignType
WHEN OTHER MOVE 13 TO SignType
END-EVALUATE.
EXIT PROGRAM.
END PROGRAM IdentifySign.
END PROGRAM Listing16-9.
433
Chapter 17
Direct Access Files
When I learned COBOL many years ago, direct access files, and particularly indexed files, were the jewel in COBOL’s crown. No other mainstream programming language provided native support for file organizations of such versatility.
Nowadays, the predominance of databases means that the importance of direct access files in modern COBOL
programming is greatly reduced. Nevertheless, the huge inventory of legacy programs that still use direct access files makes these file organizations a worthwhile topic of discussion.
This chapter introduces you to COBOL’s direct access file organizations: indexed and relative files. These organizations are called direct access organizations because they allow you to access data records directly based on a key field. Direct access files are more versatile than sequential files. They let you update or delete records in situ and access records sequentially or directly using a key field. Needless to say, direct access files only work on direct access media such as hard disks. You can’t use
indexed or relative files with serial media such as magnetic tapes. To take advantage of the versatility of direct access files, you use a number of new COBOL verbs and concepts. This chapter introduces the DELETE, REWRITE, and START verbs and the concepts of file status, the key of reference, and the next-record pointer.
Sequential, indexed, and relative file organizations all have strengths and weaknesses. No one organization is best for all situations. This chapter concludes with a discussion of the advantages and disadvantages of all the COBOL
file organizations and when you should use one rather than another.
Direct Access vs.Sequential Files
As you learned in Chapter 10, access to records in a sequential file is serial. To reach a particular record, you must read all the preceding records. You also learned that if the sequential file is unordered, the only practical operations are to read records from the file or add records to the end of the file. It is impractical to update records or delete records in an unordered sequential file. In addition, even if the file is ordered, inserting, updating, or deleting records is a problem because when you apply these operations, you must preserve the ordering of the file—and the only way to do that is to create a copy of the file to which these operations have been applied.
Although sequential files have a number of advantages over other types of file organization (as discussed in the final section of this chapter), the fact that you must create a new file when you delete, update, or insert records is problematic.
These problems are addressed by direct access files. Direct access files allow you to read, update, delete, and insert individual records in situ on the basis of a key value. For instance, to delete a customer record in a direct access file, you supply the customer ID of the record to be deleted and then execute a DELETE statement.
In COBOL, there are two direct access file organizations: relative files and indexed files.
435
Chapter 17 ■ DireCt aCCess Files
Organization of Relative Files
Before you see how relative files are declared and used, let’s look at how they are organized. As you can see from the schematic representation in Figure 17-1, the records in a relative file are organized on ascending relative record number. You can visualize a relative file as a one-dimensional table stored on disk, and you can think of the relative record number as the index into that table.
Figure 17-1. Schematic representation of a relative file
Some restrictions should be obvious from Figure 17-1. First, only one relative key is supported, and that key must be numeric and take a value between 1 and the number of the highest relative record written to the file. Another restriction is that, even when the file is only sparsely populated, enough disk space has to be allocated to hold all the records between 1 and the record with the highest relative record number. For instance, if a record with a relative record number of 150,000 is written to the file, then room sufficient for 150,000 records is allocated to the file—even though that may be the only record actually written to the file. You can see this illustrated in Figure 17-1. In the example file, the record with the highest relative record number is 5,888, so disk space sufficient to store 5,888 records has been allocated. However, not all the record locations contain records. The record areas labelled “free” have been allocated but have not yet had record values written to them.
Being restricted to a single numeric key in a defined range is onerous, but there are ways to loosen the shackles.
For instance, you might add a base value to the relative record number to change the range. For instance, in Figure 17-1
you could use a base of 10,000 so that the first record key value would be 10,001 and the last would be 15,888. Obviously, before you used the key, you would subtract 10,000 to convert it into the relative record number.
Using a base value is a very simple key transformation, and in COBOL this is probably about as much
manipulation as you want to do. In other languages, you might write a sophisticated hashing algorithm to map even alphanumeric keys onto range of relative record numbers; but in COBOL, when you need keys with this level of sophistication, you use indexed files.
436
Chapter 17 ■ DireCt aCCess Files
In addition to showing how records are organized in a relative file, Figure 17-1 also shows how updates, insertions and, deletions are applied:
• To update a record, you use the relative record number to READ the record from the file into the
record buffer. Then you make the changes to the record data and REWRITE the record to the file.
• To insert a record, you use the relative record number to tell the system where to WRITE the
record. Obviously, the allocated space must be free, or an error condition will occur.
• To delete a record, you use the relative record number to tell the system which record to
DELETE. Obviously, the record must exist. For instance, in Figure 17-1, an error condition would occur if you tried to delete the record with the relative record number 5,887 because
there is no record in that position. In a relative file, when you delete a record, all the file system
does is to mark it as deleted. It does not really delete the record.
Processing Relative Files
As mentioned at the beginning of this chapter, direct access files are declared and processed using a number of new declaration clauses and verbs. Instead of boring you with a dry, formal introduction, this section shows you some simple examples. Once you have a feel for how it all works, I introduce the required clauses and verbs more formally.
Let’s start with a simple program that reads a relative file both sequentially and directly. Then you learn how to create a relative file from a sequential file. Most programming environments have tools that allow you to do this, but it is interesting to see how to do it by hand. The final example shows you how to apply a file of transactions to the relative file.
Reading a Relative File
The program in Listing 17-1 reads a relative file either sequentially or directly, depending on the choice made by the user.
Listing 17-1. Reading a Relative File Sequentially or Directly Using a Key
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing17-1.
AUTHOR. MICHAEL COUGHLAN.
* Reads a Relative file directly or in sequence
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT VehicleFile ASSIGN TO "Listing17-1.DAT"
ORGANIZATION IS RELATIVE
ACCESS MODE IS DYNAMIC
RELATIVE KEY IS VehicleKey
FILE STATUS IS VehicleStatus.
DATA DIVISION.
FILE SECTION.
FD VehicleFile.
01 VehicleRec.
88 EndOfVehiclefile VALUE HIGH-VALUES.
02 VehicleNum PIC 9(4).
02 VehicleDesc PIC X(25).
02 ManfName PIC X(20).
437
Chapter 17 ■ DireCt aCCess Files
WORKING-STORAGE SECTION.
01 VehicleStatus PIC X(2).
88 RecordFound VALUE "00".
01 VehicleKey PIC 9(4).
01 ReadType PIC 9.
88 DirectRead VALUE 1.
88 SequentialRead VALUE 2.
01 PrnVehicleRecord.
02 PrnVehicleNum PIC 9(4).
02 PrnVehicleDesc PIC BBX(25).
02 PrnManfName PIC BBX(20).
PROCEDURE DIVISION.
BEGIN.
OPEN INPUT VehicleFile
DISPLAY "Read type : Direct read = 1, Sequential read = 2 --> "
WITH NO ADVANCING.
ACCEPT ReadType
IF DirectRead
DISPLAY "Enter vehicle key (4 digits) --> " WITH NO ADVANCING
ACCEPT VehicleKey
READ VehicleFile
INVALID KEY DISPLAY "Vehicle file status = " VehicleStatus
/>
END-READ
PERFORM DisplayRecord
END-IF
IF SequentialRead
READ VehicleFile NEXT RECORD
AT END SET EndOfVehiclefile TO TRUE
END-READ
PERFORM UNTIL EndOfVehiclefile
PERFORM DisplayRecord
READ VehicleFile NEXT RECORD
AT END SET EndOfVehiclefile TO TRUE
END-READ
END-PERFORM
END-IF
CLOSE VehicleFile
STOP RUN.
DisplayRecord.
IF RecordFound
MOVE VehicleNum TO PrnVehicleNum
MOVE VehicleDesc TO PrnVehicleDesc
MOVE ManfName TO PrnManfName
DISPLAY PrnVehicleRecord
END-IF.
438
Chapter 17 ■ DireCt aCCess Files
The first thing to note is that the SELECT and ASSIGN clause has a number of new entries. First, ORGANIZATION is now RELATIVE. Second, because a relative file allows you to access the records in the file directly or sequentially, you must have an ACCESS MODE phrase to say what kind of access you desire on the file. Three types of access are available: RANDOM (key-based access only), SEQUENTIAL (sequential only), and DYNAMIC (a mixture of keyed and sequential access). Third, to allow key-based access, you must specify a RELATIVE KEY phrase to tell the system where it can find the key value used for direct access. Note that the key mentioned here cannot be part of the record description.
The final entry is the FILE STATUS clause. The FILE STATUS clause allows you to identify a two-character area of storage to hold 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 on the file, some value is returned to FILE STATUS indicating whether the operation was successful. I introduce these FILE STATUS values as and when they occur; for this program, you only need to know that a value of "00" indicates that the operation (READ, in this case) was successful.
The FILE STATUS clause is not restricted to direct access files. You can use it with sequential files, but that isn’t necessary because with those files there are not many states that you need to detect. However, with direct access files, a number of file states need to be detected. For instance, you need to detect when an attempt is made to READ, DELETE, or REWRITE a record when a record with that key value does not exist in the file. Similarly, you need to be able to detect when an attempt to WRITE a record finds that there is already a record with that key value in the file.
Michael Coughlan Page 53