On Day 11, "Indexed File I/O," you learned that it is possible to set up more than one key in a file, in order to retrieve records in a different order than they were entered. You saw examples of how to retrieve in alphabetical and numerical order, and today's lesson teaches you the specifics of completing this task. You also learn about the following topics:
Although an indexed file must have a unique primary key, it is possible to put other keys in the file. These keys do not have to be unique and can be arranged to return records in a different order than the primary key. Alternate keys are useful for retrieving records in alphabetical order by name, in zip code order, or any of a variety of other sort orders. A sales file could include an alternate key on the customer territory to group information in territory order. An employee file could contain an alternate key on the employment date to provide a sort on seniority of the employee.
Today, you use one of these alternate keys to provide a method of accessing the vendor file in alphabetical vendor name order.
New Term: An alternate index or alternate key is an additional index in an indexed file that defines an alternative path along which records can be retrieved. The term path is used because when you use an alternate index to read records one after the other in a file, the records are read in a different sequence than they would be read using a standard READ NEXT.
An indexed file containing alternate indexes still must have a primary key, but it usually is called an alternate indexed file to indicate the existence of the extra keys.
An alternate indexed file is defined in the same way as an indexed file, but some additional information appears in the SELECT statement for the file.
Listing 17.1 is a COPY file containing an FD for an alternate indexed file. Note that it is no different from earlier versions of the FD for the vendor file, except that it includes a comment that VENDOR-NAME is an alternate key with duplicates. The comment does not create an alternate key, and is only there for reference.
000100*-------------------------------- 000200* FDVND04.CBL 000300* Primary Key - VENDOR-NUMBER 000400* Alternate - NAME with duplicates 000500 000600* NAME, ADDRESS-1, CITY, STATE, 000700* and PHONE are required fields. 000800* 000900* VENDOR-STATE must be looked up 001000* and must exist in the STATE-FILE 001100* to be valid. 001200* VENDOR-ADDRESS-2 not always used 001300* so may be SPACES 001400* VENDOR-PHONE is usually the 001500* number for VENDOR-CONTACT 001600* All fields should be entered in 001700* UPPER case. 001800*-------------------------------- 001900 FD VENDOR-FILE 002000 LABEL RECORDS ARE STANDARD. 002100 01 VENDOR-RECORD. 002200 05 VENDOR-NUMBER PIC 9(5). 002300 05 VENDOR-NAME PIC X(30). 002400 05 VENDOR-ADDRESS-1 PIC X(30). 002500 05 VENDOR-ADDRESS-2 PIC X(30). 002600 05 VENDOR-CITY PIC X(20). 002700 05 VENDOR-STATE PIC X(2). 002800 05 VENDOR-ZIP PIC X(10). 002900 05 VENDOR-CONTACT PIC X(30). 003000 05 VENDOR-PHONE PIC X(15). 003100
Listing 17.2 is a COPY file containing a SELECT statement for an alternate indexed file, and this is where the alternate key is actually defined.
000100*-------------------------------- 000200* SLVND02.CBL 000300*-------------------------------- 000400 SELECT VENDOR-FILE 000500 ASSIGN TO "vendor" 000600 ORGANIZATION IS INDEXED 000700 RECORD KEY IS VENDOR-NUMBER 000800 ALTERNATE KEY 000900 IS VENDOR-NAME WITH DUPLICATES 001000 ACCESS MODE IS DYNAMIC. 001100
ANALYSIS: At lines 000800 and 000900, the alternate key is identified as VENDOR-NAME. The WITH DUPLICATES clause on line 000900 indicates that more than one record can exist with the same value in this field. Allowing duplicates in an alternate key field for names is a standard practice because names can be duplicated. If the WITH DUPLICATES clause is omitted, VENDOR-NAME tends to act like a second primary key on the file, and it forces each value in the key to be unique.
If an alternate indexed file is defined with an alternate key in which duplicates are not allowed, attempting to write a record with a key that already is on file has the same effect as attempting to write a file with a duplicate primary key. An INVALID KEY file error condition occurs because a record with that key value already is on file.
Adding the definition in a SELECT statement does not by itself make an alternate indexed file. The file must have been created (opened in output mode) by a program containing that definition for the file.
After the file is created, you can treat it like any other indexed file. Records written to it will be stored correctly with the alternate index values.
Opening a file in output mode destroys the original file if one exists. This presents a problem. You already have created a vendor file without an alternate index and put several records in it. Now you need a new file with the alternate key included. It is possible to convert the original file without losing the data by using the records in the original file and writing them to the new file that has been created.
The method used for this is a program that opens the original file for reading, opens the new file for output, and then copies records from the old file to the new file.
Recall that when using a COBOL program to open a file, I said that the file must be opened with the same file definition that was used to create it. Now that you are more familiar with COBOL, I am going to change that statement.
In order to sort this out, you need to delve into the inner workings of an indexed file. STATE-FILE is used in this example because the records are shorter and easier to display, but the principle is the same for the vendor file.
What's in a data file? Regardless of whether the file is indexed, the primary content of a data file is data. Figure 17.1 represents the state code file containing five records. The figure also includes a ruler for the 22 bytes in each record.
Figure 17.1.
Five records in a state codes file.
The file contains five records of 22 bytes each. The first two bytes of each record is the two-character code for that state. The remaining 20 bytes contain the state name followed by spaces to the end of the record.
An indexed file contains the data records that have been stored in the file, but it also contains additional information. This additional data is information about the file organization, record length, primary key position and length, and any alternate keys. This information is used internally by the COBOL file system but never shows up as data when reading a file through a COBOL program.
Exactly where this information is stored in the file isn't important as long as you know that it is stored there. Figure 17.2 shows this data to indicate that it is in the file, but not as a data record.
Figure 17.2.
Five records in an indexed state codes file.
With this in mind, it is possible to clarify my earlier statement about opening a file. A file must be opened with a file definition that matches the file organization, record length, and key structure of the actual file. Usually, this is the file definition that was used to create it, but it does not have to be if it matches the file organization, record length, and key structure of that file definition.
Note that the COBOL name for the file (STATE-FILE) and the fields in the record (STATE-CODE, STATE-NAME, and so on) are not actually stored in the data file. They are stored in the COBOL program.
Listings 17.3 and 17.4 are the original SELECT and FD for the state code file.
000100*-------------------------------- 000200* SLSTATE.CBL 000300*-------------------------------- 000400 SELECT STATE-FILE 000500 ASSIGN TO "STATE" 000600 ORGANIZATION IS INDEXED 000700 RECORD KEY IS STATE-CODE 000800 ACCESS MODE IS DYNAMIC. 000900
000100*-------------------------------- 000200* FDSTATE.CBL 000300* Primary Key - STATE-CODE 000400* NAME is required 000500* NAME and CODE should be upper case 000600*-------------------------------- 000700 FD STATE-FILE 000800 LABEL RECORDS ARE STANDARD. 000900 01 STATE-RECORD. 001000 05 STATE-CODE PIC X(2). 001100 05 STATE-NAME PIC X(20). 001200
Listings 17.5 and 17.6 are another SELECT and FD that also could be used to access the same state code file. Although the data names have been changed, the file organization, record length, and key structure are the same in both definitions.
000400 SELECT ST-FILE 000500 ASSIGN TO "STATE" 000600 ORGANIZATION IS INDEXED 000700 RECORD KEY IS ST-CODE 000800 ACCESS MODE IS DYNAMIC. 000900
000700 FD ST-FILE 000800 LABEL RECORDS ARE STANDARD. 000900 01 ST-RECORD. 001000 05 ST-CODE PIC X(2). 001100 05 ST-NAME PIC X(20). 001200
If you used Listings 17.5 and 17.6 in a program, you would use the data names from these listings to access the file. When you open the file, you would OPEN I-O ST-FILE. To write the record, you would use WRITE ST-RECORD, but the file would still be accessed correctly.
Listings 17.7 and 17.8 are an extreme (and possibly silly) example of changing things around. The record originally was defined as two fields. What was STATE-CODE is now named THE-KEY, and the 20-character field that was called STATE-NAME is broken up arbitrarily into three smaller fields. Even with the changes, the file organization, record length, and key structure remain the same. This pair of file definitions could be used to open and process the state code file. Of course, using FIRST-5-OF-NAME for anything represents only the first five characters of the original STATE-NAME. 2ND-5-OF-NAME or LAST-10-OF-NAME represents other portions of the original STATE-NAME. It is useless to do something like this, but this extreme example illustrates the point very well.
000400 SELECT THE-FILE 000500 ASSIGN TO "STATE" 000600 ORGANIZATION IS INDEXED 000700 RECORD KEY IS THE-KEY 000800 ACCESS MODE IS DYNAMIC. 000900
000700 FD THE-FILE 000800 LABEL RECORDS ARE STANDARD. 000900 01 THE-RECORD. 001000 05 THE-KEY PIC X(2). 001100 05 FIRST-5-OF-NAME PIC X(5). 001200 05 2ND-5-OF-NAME PIC X(5). 001300 05 LAST-10-OF-NAME PIC X(10).
There are times when a redefinition of the fields in a record can be useful. Suppose that one program that uses the STATE-FILE calculates shipping charges based on whether the shipping address is within the continental United States. The program currently has logic such as that shown in Listing 17.9. It is not a good practice to hard-code special conditions like this, but you will find it in programs that you are asked to modify all the time.
021000* Add extra shipping for Alaska and Hawaii 021100 IF STATE-CODE = "HI" OR STATE-CODE = "AK" 021200 PERFORM CHARGE-EXTRA-SHIPPING 021300 ELSE 021400 PERFORM CHARGE-REGULAR-SHIPPING.
This code keeps working until the business expands and you need to include state codes for U.S. territories and Canadian provinces. There are just too many of these to hard-code into the program.
By inspecting the STATE-FILE you find that none of the states uses the full 20 characters of STATE-NAME, and in every record, the 20th character of the STATE-NAME is a space.
A new FD could be defined that separates out the 20th character to use it as a continental flag as in Listing 17.10.
000100*-------------------------------- 000200* FDSTATC.CBL 000300* Primary Key - STATE-CODE 000400* NAME is required 000500* NAME and CODE should be upper case 000600*-------------------------------- 000700 FD STATE-FILE 000800 LABEL RECORDS ARE STANDARD. 000900 01 STATE-RECORD. 001000 05 STATE-CODE PIC X(2). 001100 05 STATE-NAME PIC X(19). 001200 05 STATE-CONTINENTAL PIC X(1).
After setting the flag correctly to Y or N for each state, you could test the flag to determine shipping charges as in Listing 17.11.
021000* Add extra shipping for non-continental US 021100 IF STATE-CONTINENTAL = "N" 021200 PERFORM CHARGE-EXTRA-SHIPPING 021300 ELSE 021400 PERFORM CHARGE-REGULAR-SHIPPING.
This method of allocating unused characters in existing fields for new fields is a very common practice.
File and data conversions such as adding STATE-CONTINENTAL, and the following conversion of the VENDOR-FILE are very typical tasks that might be assigned to a junior programmer. Being able to do conversions is one way you will be able to perform useful (and paid) work.
You have several things to deal with before you can create a new vendor file out of the existing one. The data names in a program must not be identical, so it is necessary to create a temporary SELECT and FD that can be used to open the original file, but use different data names.
Another problem has to do with the way files are stored on a disk. Two files cannot have the same physical name on a disk. The new file will be called "vendor", so for the purpose of conversion, the old file is renamed "ovendor".
Under MS-DOS, enter the following:
DIR vendor*
If you are using Micro Focus Personal COBOL, two files are named vendor: VENDOR and VENDOR.IDX. Under ACUCOBOL, one file is named VENDOR. Under other COBOL compilers, two files might be named VENDOR.DAT and VENDOR.IDX. If your system uses two files, both of them must be renamed.
Enter one or more of these commands, depending on the filenames:
RENAME VENDOR OVENDOR RENAME VENDOR.IDX OVENDOR.IDX RENAME VENDOR.DAT OVENDOR.DAT
Listing 17.12, fdovnd01.cbl, is a COPY file of an FD that is created by copying fdvnd03.cbl to fdovnd01.cbl and then changing each data name that starts with VENDOR- so that it starts with OLD-VENDOR-.
Listing 17.13, slvnd01.cbl, is a COPY file of a SELECT statement that is created in a similar way, by copying slvnd01.cbl to slovnd01.cbl and then changing each data name that starts with VENDOR- so that it starts with OLD-VENDOR-.
Create these two files and modify each of them to match Listings 17.12 and 17.13.
000100*-------------------------------- 000200* FDOVND01.CBL 000300* Primary Key - OLD-VENDOR-NUMBER 000400* Original before alt path added 000500* NAME, ADDRESS-1, CITY, STATE, 000600* and PHONE are required fields. 000700* 000800* OLD-VENDOR-STATE must be looked up 000900* and must exist in the STATE-FILE 001000* to be valid. 001100* OLD-VENDOR-ADDRESS-2 not always used 001200* so may be SPACES 001300* OLD-VENDOR-PHONE is usually the 001400* number for OLD-VENDOR-CONTACT 001500* All fields should be entered in 001600* UPPER case. 001700*-------------------------------- 001800 FD OLD-VENDOR-FILE 001900 LABEL RECORDS ARE STANDARD. 002000 01 OLD-VENDOR-RECORD. 002100 05 OLD-VENDOR-NUMBER PIC 9(5). 002200 05 OLD-VENDOR-NAME PIC X(30). 002300 05 OLD-VENDOR-ADDRESS-1 PIC X(30). 002400 05 OLD-VENDOR-ADDRESS-2 PIC X(30). 002500 05 OLD-VENDOR-CITY PIC X(20). 002600 05 OLD-VENDOR-STATE PIC X(2). 002700 05 OLD-VENDOR-ZIP PIC X(10). 002800 05 OLD-VENDOR-CONTACT PIC X(30). 002900 05 OLD-VENDOR-PHONE PIC X(15). 003000
For the SELECT statement, be sure to change line 000500 to read ASSIGN TO "ovendor".
000100*-------------------------------- 000200* SLOVND01.CBL 000300*-------------------------------- 000400 SELECT OLD-VENDOR-FILE 000500 ASSIGN TO "ovendor" 000600 ORGANIZATION IS INDEXED 000700 RECORD KEY IS OLD-VENDOR-NUMBER 000800 ACCESS MODE IS DYNAMIC.
After these new file definitions are created, it is possible to write a program that converts the old file to the new by reading each record in the old file and writing it to the new file (shown in Listing 17.14).
000100 IDENTIFICATION DIVISION. 000200 PROGRAM-ID. NEWVND01. 000300*------------------------------------------------ 000400* Create new Vendor File with Alt key from old. 000500*------------------------------------------------ 000600 ENVIRONMENT DIVISION. 000700 INPUT-OUTPUT SECTION. 000800 FILE-CONTROL. 000900 001000 COPY "SLOVND01.CBL". 001100 001200 COPY "SLVND02.CBL". 001300 DATA DIVISION. 001400 FILE SECTION. 001500 001600 COPY "FDOVND01.CBL". 001700 001800 COPY "FDVND04.CBL". 001900 002000 WORKING-STORAGE SECTION. 002100 002200 77 OLD-VENDOR-FILE-AT-END PIC X VALUE "N". 002300 002400 PROCEDURE DIVISION. 002500 PROGRAM-BEGIN. 002600 PERFORM OPENING-PROCEDURE. 002700 PERFORM MAIN-PROCESS. 002800 PERFORM CLOSING-PROCEDURE. 002900 003000 PROGRAM-DONE. 003100 STOP RUN. 003200 003300 OPENING-PROCEDURE. 003400 OPEN OUTPUT VENDOR-FILE. 003500 OPEN I-O OLD-VENDOR-FILE. 003600 003700 CLOSING-PROCEDURE. 003800 CLOSE VENDOR-FILE. 003900 CLOSE OLD-VENDOR-FILE. 004000 004100 MAIN-PROCESS. 004200 PERFORM READ-NEXT-OLD-VENDOR-RECORD. 004300 PERFORM PROCESS-ONE-RECORD 004400 UNTIL OLD-VENDOR-FILE-AT-END = "Y". 004500 004600 READ-NEXT-OLD-VENDOR-RECORD. 004700 MOVE "N" TO OLD-VENDOR-FILE-AT-END. 004800 READ OLD-VENDOR-FILE NEXT RECORD 004900 AT END 005000 MOVE "Y" TO OLD-VENDOR-FILE-AT-END. 005100 005200 PROCESS-ONE-RECORD. 005300 MOVE OLD-VENDOR-RECORD TO VENDOR-RECORD. 005400 PERFORM WRITE-VENDOR-RECORD. 005500 005600 PERFORM READ-NEXT-OLD-VENDOR-RECORD. 005700 005800 WRITE-VENDOR-RECORD. 005900 WRITE VENDOR-RECORD 006000 INVALID KEY 006100 DISPLAY "ERROR WRITING VENDOR RECORD". 006200 006300
ANALYSIS: Listing 17.14 is a fairly straightforward program. In the OPENING-PROCEDURE at line 003300, it opens the VENDOR-FILE in output mode. This creates the new vendor file with the alternate index. It then opens OLD-VENDOR-FILE (ovendor) in I/O mode.
The loop control in MAIN-PROCESS at line 004100 follows the procedure of reading the first old vendor record and then performing the processing loop (PROCESS-ONE-RECORD) until OLD-VENDOR-FILE-AT-END = "Y".
The processing loop, PROCESS-ONE-RECORD at line 005200, moves the OLD-VENDOR-RECORD to VENDOR-RECORD, writes the new record, and then at the end of the loop at line 005600, reads the next old vendor record.
Code and compile this program. Be sure that you have renamed the vendor file to "ovendor" before you run it. The new file named "vendor" will contain an alternate index. You won't notice any difference in the file yet, although the file might be larger on the disk.
You have to modify the maintenance program for the vendor file, vndmnt02.cbl, to allow for the new key in the file. The maintenance for a file with alternate keys can be identical to the maintenance for a standard indexed file. To modify vndmnt02.cbl so that it will maintain the new vendor file, copy it to vndmnt03.cbl. Then make the changes at lines 001100 and 001800 of Listing 17.15, a fragment of vndmnd03.cbl, to include the new SELECT and FD for the vendor file.
000100 IDENTIFICATION DIVISION. 000200 PROGRAM-ID. VNDMNT03. 000300*-------------------------------- 000400* Add, Change, Inquire and Delete 000500* for the Vendor File. 000600*-------------------------------- 000700 ENVIRONMENT DIVISION. 000800 INPUT-OUTPUT SECTION. 000900 FILE-CONTROL. 001000 001100 COPY "SLVND02.CBL". 001200 001300 COPY "SLSTATE.CBL". 001400 001500 DATA DIVISION. 001600 FILE SECTION. 001700 001800 COPY "FDVND04.CBL". 001900 002000 COPY "FDSTATE.CBL". 002100
Make the changes and compile the program so that you have a maintenance program for the new vendor file.
Listing 17.16 illustrates a customer record with a primary key of CUSTOMER-NUMBER. This is a fairly straightforward record layout, except that the phone number has been broken down additionally into area code, prefix, and number.
001000 01 CUSTOMER-RECORD. 001100 05 CUSTOMER-NUMBER PIC 9(5). 001200 05 CUSTOMER-NAME PIC X(20). 001300 05 CUSTOMER-ADDRESS-1 PIC X(20). 001400 05 CUSTOMER-ADDRESS-2 PIC X(20). 001500 05 CUSTOMER-ZIP PIC 9(5). 001600 05 CUSTOMER-PHONE. 001700 10 CUSTOMER-AREA-CODE PIC 9(3). 001800 10 CUSTOMER-PREFIX PIC 9(3). 001900 10 CUSTOMER-PHONE-NO PIC 9(4).
A field can be named as an alternate index so that, as each record is added to the file, information also is stored in the alternate index area of the file to indicate the correct order of records for that alternate index.
If you displayed the records in a customer file in primary key order, the file might look somewhat haphazard. This would be reading and displaying the file along the primary key path.
If you request that the name field be used as an index, and that records be presented to you in the order of the name index, they arrive in the order shown in Figure 17.3, along the CUSTOMER-NAME key path.
Figure 17.3.
Records sorted on the name field.
If you also request that the zip code and area code be used as an index for the records, you can have the records arrive in zip code order (as in Figure 17.4) along the CUSTOMER-ZIP key path, or in area-code order (as in Figure 17.5) along the CUSTOMER-AREA-CODE key path.
Figure 17.4.
Records sorted on the zip code field.
Figure 17.5.
Records sorted on the area code field.
In all the examples, the alternate indexed fields were fields in which duplicates might, and in fact do, occur. Amphora Inc. and Malio Bros. both have the same zip code and area code. In a large customer base, it is possible that customer names would be duplicated.
New Term: The key path is the natural sorted order of records as they are read from the file using a particular key.
Listing 17.17 shows an example of the syntax that is used to define a file such as the customer file with multiple keys.
000400 SELECT CUSTOMER-FILE 000500 ASSIGN TO "CUSTOMER" 000600 ORGANIZATION IS INDEXED 000700 RECORD KEY IS CUSTOMER-NUMBER 000800 ALTERNATE KEY IS CUSTOMER-NAME WITH DUPLICATES 000900 ALTERNATE KEY IS CUSTOMER-ZIP WITH DUPLICATES 001000 ALTERNATE KEY IS CUSTOMER-AREA-CODE WITH DUPLICATES 001100 ACCESS MODE IS DYNAMIC. 001200
When an alternate indexed file is opened, the key path is set to the primary key. If you READ NEXT through the file, the records will be returned in the order of the primary key. COBOL includes a command that enables you to change the key path--the START command.
The first step to using a START command is to move a value to the field that will be the new key. In the case of the vendor file, the alternate key is the VENDOR-NAME. To set the file up to be able to read all records in VENDOR-NAME order, move the lowest possible value to the VENDOR-NAME (MOVE SPACES TO VENDOR-NAME). After the key is set up, you are ready for the second step. Start the file using the START command.
Listing 17.18 is an example of starting on a new key. What you want to do is start the file at the first record that contains a VENDOR-NAME that is greater than or equal to the spaces that are now in VENDOR-NAME. It seems that you should be able to say START GREATER THAN OR EQUAL. You can under the new COBOL-85 standard, but before that option was added you were limited to a little more awkward syntax. It uses the complement of greater than or equal to which is NOT LESS THAN. In this example, NOT < (NOT LESS THAN) is used to start at the first record whose VENDOR-NAME is equal to or greater than spaces.
020000 MOVE SPACE TO VENDOR-NAME. 020100 START VENDOR-FILE 020200 KEY NOT < VENDOR-NAME 020300 INVALID KEY 020400 MOVE "Y" TO FILE-AT-END.
You can do some interesting positioning tricks using the START command. In Listing 17.19, the key is initialized to an A followed by all Zs, and the start is GREATER THAN the key value. This causes the start to position the file at the first record with a VENDOR-NAME greater than "AZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", which probably would be the first vendor name that started with B.
020000 MOVE "AZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" TO VENDOR-NAME. 020100 START VENDOR-FILE 020200 KEY > VENDOR-NAME 020300 INVALID KEY 020400 MOVE "Y" TO FILE-AT-END.
The START command originally supported three conditions for determining the starting position, EQUALS, GREATER THAN, and NOT LESS THAN. The COBOL-85 standard added GREATER THAN OR EQUAL TO ( >= ). Some vendors have extended these to include positioning for LESS THAN, NOT GREATER THAN, and LESS THAN OR EQUAL TO. Here is the syntax for the standard three and the COBOL-85 option:
START file name KEY NOT < key name [ INVALID KEY do something ] START file name KEY > key name [ INVALID KEY do something ] START file name KEY EQUALS key name [ INVALID KEY do something ] START file name KEY GREATER THAN OR EQUAL TO key name [ INVALID KEY do something ]
The following are examples:
MOVE SPACE TO VENDOR-NAME. START VENDOR-FILE KEY NOT < VENDOR-NAME INVALID KEY MOVE "Y" TO FILE-AT-END. MOVE "AZZZZZZZZZZZZZZZZZZZ" TO VENDOR-NAME. START VENDOR-FILE KEY > VENDOR-NAME INVALID KEY MOVE "Y" TO FILE-AT-END. MOVE "JONES AND SONS" TO VENDOR-NAME. START VENDOR-FILE KEY EQUALS VENDOR-NAME INVALID KEY MOVE "N" TO RECORD-FOUND. START VENDOR-FILE KEY GREATER THAN OR EQUAL TO VENDOR-NAME INVALID KEY MOVE "Y" TO FILE-AT-END.
You will usually use START NOT < or the newer START >= (GREATER THAN OR EQUAL TO), which are the most common types of START used in programs. When the START is completed successfully, the key path is changed and any subsequent READ NEXT proceeds to the next record along that path automatically.
The START has two effects: It changes the key path, and it positions the file someplace on that key path. It most commonly is used to position at the beginning of a key path.
A START does not read or acquire a record; it only positions the file ready for a READ or READ NEXT. If you use START NOT LESS THAN ( NOT < ) or START GREATER THAN ( > ), the start does not actually read a record. It positions the file so that a READ NEXT will read the record that matches the START condition. You see an example of this in Listing 17.20, the vendor-by-name report.
000100 IDENTIFICATION DIVISION. 000200 PROGRAM-ID. VNBYNM01. 000300*-------------------------------- 000400* Report on the Vendor File in 000500* alphabetical name order. 000600*-------------------------------- 000700 ENVIRONMENT DIVISION. 000800 INPUT-OUTPUT SECTION. 000900 FILE-CONTROL. 001000 001100 COPY "SLVND02.CBL". 001200 001300 COPY "SLSTATE.CBL". 001400 001500 SELECT PRINTER-FILE 001600 ASSIGN TO PRINTER 001700 ORGANIZATION IS LINE SEQUENTIAL. 001800 001900 DATA DIVISION. 002000 FILE SECTION. 002100 002200 COPY "FDVND04.CBL". 002300 002400 COPY "FDSTATE.CBL". 002500 002600 FD PRINTER-FILE 002700 LABEL RECORDS ARE OMITTED. 002800 01 PRINTER-RECORD PIC X(80). 002900 003000 WORKING-STORAGE SECTION. 003100 003200 01 DETAIL-LINE. 003300 05 PRINT-NUMBER PIC 9(5). 003400 05 FILLER PIC X VALUE SPACE. 003500 05 PRINT-NAME PIC X(30). 003600 05 FILLER PIC X(15) VALUE SPACE. 003700 05 PRINT-CONTACT PIC X(30). 003800 003900 01 CITY-STATE-LINE. 004000 05 FILLER PIC X(6) VALUE SPACE. 004100 05 PRINT-CITY PIC X(20). 004200 05 FILLER PIC X VALUE SPACE. 004300 05 PRINT-STATE PIC X(2). 004400 05 FILLER PIC X VALUE SPACE. 004500 05 PRINT-STATE-NAME PIC X(20). 004600 05 FILLER PIC X(1) VALUE SPACE. 004700 05 PRINT-ZIP PIC X(10). 004800 004900 01 COLUMN-LINE. 005000 05 FILLER PIC X(2) VALUE "NO". 005100 05 FILLER PIC X(4) VALUE SPACE. 005200 05 FILLER PIC X(12) VALUE "NAME-ADDRESS". 005300 05 FILLER PIC X(33) VALUE SPACE. 005400 05 FILLER PIC X(17) VALUE "CONTACT-PHONE-ZIP". 005500 005600 01 TITLE-LINE. 005700 05 FILLER PIC X(20) VALUE SPACE. 005800 05 FILLER PIC X(24) 005900 VALUE "VENDOR ALPHABETICAL LIST". 006000 05 FILLER PIC X(11) VALUE SPACE. 006100 05 FILLER PIC X(5) VALUE "PAGE:". 006200 05 FILLER PIC X(1) VALUE SPACE. 006300 05 PRINT-PAGE-NUMBER PIC ZZZZ9. 006400 006500 77 FILE-AT-END PIC X. 006600 77 STATE-FILE-AT-END PIC X VALUE "N". 006700 77 LINE-COUNT PIC 999 VALUE ZERO. 006800 77 PAGE-NUMBER PIC 99999 VALUE ZERO. 006900 77 MAXIMUM-LINES PIC 999 VALUE 55. 007000 007100 01 TABLE-STATE-RECORD OCCURS 50 TIMES 007200 INDEXED BY STATE-INDEX. 007300 05 TABLE-STATE-CODE PIC XX. 007400 05 TABLE-STATE-NAME PIC X(20). 007500 01 NUMBER-OF-STATES PIC 99 VALUE 50. 007600 PROCEDURE DIVISION. 007700 PROGRAM-BEGIN. 007800 007900 PERFORM OPENING-PROCEDURE. 008000 MOVE ZEROES TO LINE-COUNT 008100 PAGE-NUMBER. 008200 008300 PERFORM START-NEW-PAGE. 008400 008500 MOVE "N" TO FILE-AT-END. 008600 PERFORM READ-FIRST-RECORD. 008700 IF FILE-AT-END = "Y" 008800 MOVE "NO RECORDS FOUND" TO PRINTER-RECORD 008900 PERFORM WRITE-TO-PRINTER 009000 ELSE 009100 PERFORM PRINT-VENDOR-FIELDS 009200 UNTIL FILE-AT-END = "Y". 009300 009400 PERFORM CLOSING-PROCEDURE. 009500 009600 PROGRAM-DONE. 009700 STOP RUN. 009800 009900 OPENING-PROCEDURE. 010000 OPEN I-O VENDOR-FILE. 010100 010200 OPEN I-O STATE-FILE. 010300 PERFORM LOAD-STATE-TABLE. 010400 CLOSE STATE-FILE. 010500 010600 OPEN OUTPUT PRINTER-FILE. 010700 010800 LOAD-STATE-TABLE. 010900 PERFORM CLEAR-TABLE. 011000 SET STATE-INDEX TO 1. 011100 PERFORM READ-NEXT-STATE-RECORD. 011200 PERFORM LOAD-ONE-STATE-RECORD 011300 UNTIL STATE-FILE-AT-END = "Y" OR 011400 STATE-INDEX > NUMBER-OF-STATES. 011500 011600 CLEAR-TABLE. 011700 PERFORM CLEAR-ONE-TABLE-ROW 011800 VARYING STATE-INDEX FROM 1 BY 1 011900 UNTIL STATE-INDEX > NUMBER-OF-STATES. 012000 012100 CLEAR-ONE-TABLE-ROW. 012200 MOVE SPACE TO TABLE-STATE-RECORD(STATE-INDEX). 012300 012400 LOAD-ONE-STATE-RECORD. 012500 MOVE STATE-CODE TO TABLE-STATE-CODE(STATE-INDEX). 012600 MOVE STATE-NAME TO TABLE-STATE-NAME(STATE-INDEX). 012700 012800 PERFORM READ-NEXT-STATE-RECORD. 012900 013000 IF STATE-FILE-AT-END NOT = "Y" 013100 SET STATE-INDEX UP BY 1 013200 IF STATE-INDEX > NUMBER-OF-STATES 013300 DISPLAY "TABLE FULL". 013400 013500 CLOSING-PROCEDURE. 013600 CLOSE VENDOR-FILE. 013700 PERFORM END-LAST-PAGE. 013800 CLOSE PRINTER-FILE. 013900 014000 PRINT-VENDOR-FIELDS. 014100 IF LINE-COUNT > MAXIMUM-LINES 014200 PERFORM START-NEXT-PAGE. 014300 PERFORM PRINT-THE-RECORD. 014400 PERFORM READ-NEXT-RECORD. 014500 014600 PRINT-THE-RECORD. 014700 PERFORM PRINT-LINE-1. 014800 PERFORM PRINT-LINE-2. 014900 PERFORM PRINT-LINE-3. 015000 PERFORM PRINT-LINE-4. 015100 PERFORM LINE-FEED. 015200 015300 PRINT-LINE-1. 015400 MOVE SPACE TO DETAIL-LINE. 015500 MOVE VENDOR-NUMBER TO PRINT-NUMBER. 015600 MOVE VENDOR-NAME TO PRINT-NAME. 015700 MOVE VENDOR-CONTACT TO PRINT-CONTACT. 015800 MOVE DETAIL-LINE TO PRINTER-RECORD. 015900 PERFORM WRITE-TO-PRINTER. 016000 016100 PRINT-LINE-2. 016200 MOVE SPACE TO DETAIL-LINE. 016300 MOVE VENDOR-ADDRESS-1 TO PRINT-NAME. 016400 MOVE VENDOR-PHONE TO PRINT-CONTACT. 016500 MOVE DETAIL-LINE TO PRINTER-RECORD. 016600 PERFORM WRITE-TO-PRINTER. 016700 016800 PRINT-LINE-3. 016900 MOVE SPACE TO DETAIL-LINE. 017000 MOVE VENDOR-ADDRESS-2 TO PRINT-NAME. 017100 IF VENDOR-ADDRESS-2 NOT = SPACE 017200 MOVE DETAIL-LINE TO PRINTER-RECORD 017300 PERFORM WRITE-TO-PRINTER. 017400 017500 PRINT-LINE-4. 017600 MOVE SPACE TO CITY-STATE-LINE. 017700 MOVE VENDOR-CITY TO PRINT-CITY. 017800 MOVE VENDOR-STATE TO PRINT-STATE. 017900 018000 PERFORM LOOK-UP-STATE-CODE. 018100 018200 MOVE VENDOR-ZIP TO PRINT-ZIP. 018300 MOVE CITY-STATE-LINE TO PRINTER-RECORD. 018400 PERFORM WRITE-TO-PRINTER. 018500 018600 LOOK-UP-STATE-CODE. 018700 SET STATE-INDEX TO 1. 018800 SEARCH TABLE-STATE-RECORD 018900 AT END 019000 MOVE "***Not Found***" TO PRINT-STATE-NAME 019100 WHEN VENDOR-STATE = TABLE-STATE-CODE(STATE-INDEX) 019200 MOVE TABLE-STATE-NAME(STATE-INDEX) 019300 TO PRINT-STATE-NAME. 019400 019500 IF STATE-NAME = SPACE 019600 MOVE "*State is Blank*" TO PRINT-STATE-NAME. 019700 019800 READ-FIRST-RECORD. 019900 MOVE "N" TO FILE-AT-END. 020000 MOVE SPACE TO VENDOR-NAME. 020100 START VENDOR-FILE 020200 KEY NOT < VENDOR-NAME 020300 INVALID KEY MOVE "Y" TO FILE-AT-END. 020400 020500 IF FILE-AT-END NOT = "Y" 020600 PERFORM READ-NEXT-RECORD. 020700 020800 READ-NEXT-RECORD. 020900 READ VENDOR-FILE NEXT RECORD 021000 AT END MOVE "Y" TO FILE-AT-END. 021100 021200 WRITE-TO-PRINTER. 021300 WRITE PRINTER-RECORD BEFORE ADVANCING 1. 021400 ADD 1 TO LINE-COUNT. 021500 021600 LINE-FEED. 021700 MOVE SPACE TO PRINTER-RECORD. 021800 PERFORM WRITE-TO-PRINTER. 021900 022000 START-NEXT-PAGE. 022100 PERFORM END-LAST-PAGE. 022200 PERFORM START-NEW-PAGE. 022300 022400 START-NEW-PAGE. 022500 ADD 1 TO PAGE-NUMBER. 022600 MOVE PAGE-NUMBER TO PRINT-PAGE-NUMBER. 022700 MOVE TITLE-LINE TO PRINTER-RECORD. 022800 PERFORM WRITE-TO-PRINTER. 022900 PERFORM LINE-FEED. 023000 MOVE COLUMN-LINE TO PRINTER-RECORD. 023100 PERFORM WRITE-TO-PRINTER. 023200 PERFORM LINE-FEED. 023300 023400 END-LAST-PAGE. 023500 PERFORM FORM-FEED. 023600 MOVE ZERO TO LINE-COUNT. 023700 023800 FORM-FEED. 023900 MOVE SPACE TO PRINTER-RECORD. 024000 WRITE PRINTER-RECORD BEFORE ADVANCING PAGE. 024100 024200 READ-NEXT-STATE-RECORD. 024300 MOVE "N" TO STATE-FILE-AT-END. 024400 READ STATE-FILE NEXT RECORD 024500 AT END 024600 MOVE "Y" TO STATE-FILE-AT-END. 024700
The output of vnbynm01.cbl prints the same information as vndrpt03.cbl, but the records are in alphabetical order by name:
OUTPUT:
VENDOR ALPHABETICAL LIST PAGE: 1 NO NAME-ADDRESS CONTACT-PHONE-ZIP 00002 ABC PRINTING CHARLES JOHANSSEN 1624 FOOTHILL BLVD (818) 555-4321 SUITE 34 LOS ANGELES CA CALIFORNIA 91042 01176 ABERCROMBIE AND OTHERS 1234 45TH ST. (213) 555-6543 SUITE 17 LOS ANGELES CA CALIFORNIA 92345 00001 AERIAL SIGNS HENRIETTA MARKSON BURBANK AIRPORT (818) 555-6066 HANGAR 305 BURBANK CA CALIFORNIA 90016 00005 ALIAS SMITH AND JONES ROBIN COUSINS 1216 MAIN STREET 415 555-9203 PALO ALTO CA CALIFORNIA 90061 00022 ARTFUL DODGER 123 UNDERWOOD LANE 202 555-1234 MARKHAM WA WASHINGTON 40466 00003 CHARLES SMITH AND SONS MARTHA HARRISON 1435 SOUTH STREET (213) 555-4432 LOS ANGELES CA CALIFORNIA 90064 00014 RANIER GRAPHICS JULIA SIMPSON 4433 WASHINGTO ST (213) 555-6789 LOS ANGELES CA CALIFORNIA 90032 01440 ZINZINDORFF INC. 1604 7TH ST (213) 555-7234 LOS ANGELES CA CALIFORNIA 90404
ANALYSIS: The program is almost identical to vndrpt03.cbl. There are changes in TITLE-LINE (lines 005600 to 006300), and the program uses the new SELECT and FD for the vendor file (lines 001100 and 002200).
The main change begins at line 008600, which performs READ-FIRST-RECORD. READ-FIRST-RECORD begins at line 019800. It sets up the FILE-AT-END flag and moves spaces to the VENDOR-NAME, which will be used as the key to the file.
The START at lines 020100 through 020300 attempts to position the file so that the next READ NEXT will read a record whose VENDOR-NAME is equal to or greater than spaces.
The record has not actually been read, so at line 020600, a READ-NEXT-RECORD is requested.
One thing to note is the use of the INVALID KEY in START at line 020300. A START NOT LESS THAN positions the file so that the next READ NEXT will read a record whose value matches the start condition. If a START NOT LESS THAN fails with a file error condition (INVALID KEY), there is no next record matching the START condition. The only way there can be no next record in a file is if you are at the end of the file. If the START NOT LESS THAN fails, the INVALID KEY file error condition is used to set the FILE-AT-END flag to "Y".
How is it possible to be at the end of the file if you are starting with the lowest possible value for the VENDOR-NAME--all spaces? If a record cannot be located that contains a VENDOR-NAME equal to or greater than spaces, the data file is empty and contains no records. Using the INVALID KEY and FILE-AT-END logic, even when there seems to be no need for it, prevents file errors even if you attempt to report on a new file that contains no records.
It is important to note that aside from START, which switches the key path, the rest of the program remains basically unchanged. When the START is completed successfully, the key path is changed and READ NEXT proceeds to the next and subsequent records along that path automatically.
Figure 17.6 is a printer spacing chart for a new vendor report program, vnbynm01.cbl (vendor by name), that prints the same vendor information as vndrpt03.cbl, but in alphabetical name order.
Figure 17.6.
The spacing chart for vnbynm01.cbl.
You also can use alternate keys to help a user look up a record. Listing 17.21, vninnm01.cbl, is a vendor inquiry by name.
000100 IDENTIFICATION DIVISION. 000200 PROGRAM-ID. VNINNM01. 000300*-------------------------------- 000400* Inquire for the Vendor File 000500* using vendor name. 000600*-------------------------------- 000700 ENVIRONMENT DIVISION. 000800 INPUT-OUTPUT SECTION. 000900 FILE-CONTROL. 001000 001100 COPY "SLVND02.CBL". 001200 001300 COPY "SLSTATE.CBL". 001400 001500 DATA DIVISION. 001600 FILE SECTION. 001700 001800 COPY "FDVND04.CBL". 001900 002000 COPY "FDSTATE.CBL". 002100 002200 WORKING-STORAGE SECTION. 002300 002400 77 VENDOR-FILE-AT-END PIC X. 002500 77 STATE-RECORD-FOUND PIC X. 002600 002700 002800 77 VENDOR-NAME-FIELD PIC X(30). 002900 003000 COPY "WSCASE01.CBL". 003100 003200 PROCEDURE DIVISION. 003300 PROGRAM-BEGIN. 003400 PERFORM OPENING-PROCEDURE. 003500 PERFORM MAIN-PROCESS. 003600 PERFORM CLOSING-PROCEDURE. 003700 003800 PROGRAM-DONE. 003900 STOP RUN. 004000 004100 OPENING-PROCEDURE. 004200 OPEN I-O VENDOR-FILE. 004300 OPEN I-O STATE-FILE. 004400 004500 CLOSING-PROCEDURE. 004600 CLOSE VENDOR-FILE. 004700 CLOSE STATE-FILE. 004800 004900 MAIN-PROCESS. 005000 PERFORM INQUIRE-BY-NAME. 005100*-------------------------------- 005200* INQUIRE 005300*-------------------------------- 005400 INQUIRE-BY-NAME. 005500 PERFORM GET-EXISTING-RECORD. 005600 PERFORM INQUIRE-RECORDS 005700 UNTIL VENDOR-NAME = SPACES. 005800 005900 INQUIRE-RECORDS. 006000 PERFORM DISPLAY-ALL-FIELDS. 006100 PERFORM GET-EXISTING-RECORD. 006200 006300*-------------------------------- 006400* Locate a record logic 006500*-------------------------------- 006600 GET-EXISTING-RECORD. 006700 PERFORM ACCEPT-EXISTING-KEY. 006800 PERFORM RE-ACCEPT-EXISTING-KEY 006900 UNTIL VENDOR-FILE-AT-END NOT = "Y". 007000 007100 ACCEPT-EXISTING-KEY. 007200 PERFORM INIT-FOR-KEY-ENTRY. 007300 PERFORM ENTER-VENDOR-NAME. 007400 IF VENDOR-NAME NOT = SPACES 007500 PERFORM READ-FIRST-VENDOR-RECORD. 007600 007700 RE-ACCEPT-EXISTING-KEY. 007800 DISPLAY "RECORD NOT FOUND" 007900 PERFORM ACCEPT-EXISTING-KEY. 008000 008100*-------------------------------- 008200* Field Entry logic 008300*-------------------------------- 008400 ENTER-VENDOR-NAME. 008500 PERFORM ACCEPT-VENDOR-NAME. 008600 008700 ACCEPT-VENDOR-NAME. 008800 DISPLAY "ENTER VENDOR NAME". 008900 ACCEPT VENDOR-NAME. 009000 INSPECT VENDOR-NAME 009100 CONVERTING LOWER-ALPHA 009200 TO UPPER-ALPHA. 009300 009400*-------------------------------- 009500* Display logic 009600*-------------------------------- 009700 DISPLAY-ALL-FIELDS. 009800 DISPLAY " ". 009900 PERFORM DISPLAY-VENDOR-NUMBER. 010000 PERFORM DISPLAY-VENDOR-NAME. 010100 PERFORM DISPLAY-VENDOR-ADDRESS-1. 010200 PERFORM DISPLAY-VENDOR-ADDRESS-2. 010300 PERFORM DISPLAY-VENDOR-CITY. 010400 PERFORM DISPLAY-VENDOR-STATE. 010500 PERFORM DISPLAY-VENDOR-ZIP. 010600 PERFORM DISPLAY-VENDOR-CONTACT. 010700 PERFORM DISPLAY-VENDOR-PHONE. 010800 DISPLAY " ". 010900 011000 DISPLAY-VENDOR-NUMBER. 011100 DISPLAY " VENDOR NUMBER: " VENDOR-NUMBER. 011200 011300 DISPLAY-VENDOR-NAME. 011400 DISPLAY "1. VENDOR NAME: " VENDOR-NAME. 011500 011600 DISPLAY-VENDOR-ADDRESS-1. 011700 DISPLAY "2. VENDOR ADDRESS-1: " VENDOR-ADDRESS-1. 011800 011900 DISPLAY-VENDOR-ADDRESS-2. 012000 DISPLAY "3. VENDOR ADDRESS-2: " VENDOR-ADDRESS-2. 012100 012200 DISPLAY-VENDOR-CITY. 012300 DISPLAY "4. VENDOR CITY: " VENDOR-CITY. 012400 012500 DISPLAY-VENDOR-STATE. 012600 MOVE VENDOR-STATE TO STATE-CODE. 012700 PERFORM READ-STATE-RECORD. 012800 IF STATE-RECORD-FOUND = "N" 012900 MOVE "**Not found**" TO STATE-NAME. 013000 DISPLAY "5. VENDOR STATE: " 013100 VENDOR-STATE " " 013200 STATE-NAME. 013300 013400 DISPLAY-VENDOR-ZIP. 013500 DISPLAY "6. VENDOR ZIP: " VENDOR-ZIP. 013600 013700 DISPLAY-VENDOR-CONTACT. 013800 DISPLAY "7. VENDOR CONTACT: " VENDOR-CONTACT. 013900 014000 DISPLAY-VENDOR-PHONE. 014100 DISPLAY "8. VENDOR PHONE: " VENDOR-PHONE. 014200 014300*-------------------------------- 014400* File Related Routines 014500*-------------------------------- 014600 INIT-FOR-KEY-ENTRY. 014700 MOVE SPACE TO VENDOR-RECORD. 014800 MOVE ZEROES TO VENDOR-NUMBER. 014900 MOVE "N" TO VENDOR-FILE-AT-END. 015000 015100 READ-FIRST-VENDOR-RECORD. 015200 MOVE "N" TO VENDOR-FILE-AT-END. 015300 START VENDOR-FILE 015400 KEY NOT < VENDOR-NAME 015500 INVALID KEY 015600 MOVE "Y" TO VENDOR-FILE-AT-END. 015700 015800 IF VENDOR-FILE-AT-END NOT = "Y" 015900 PERFORM READ-NEXT-VENDOR-RECORD. 016000 016100 READ-NEXT-VENDOR-RECORD. 016200 READ VENDOR-FILE NEXT RECORD 016300 AT END 016400 MOVE "Y" TO VENDOR-FILE-AT-END. 016500 016600 READ-STATE-RECORD. 016700 MOVE "Y" TO STATE-RECORD-FOUND. 016800 READ STATE-FILE RECORD 016900 INVALID KEY 017000 MOVE "N" TO STATE-RECORD-FOUND. 017100
The output of vninnm01.cbl illustrates looking up vendors by name rather than by number. For the third entry (user entries are bold), the user enters "b" and all entries are converted to uppercase. No vendor names start with "B" in the file, so the program selects the first record that has a key equal to or greater than "B", which is CHARLES SMITH AND SONS:
OUTPUT:
ENTER VENDOR NAME abc VENDOR NUMBER: 00002 1. VENDOR NAME: ABC PRINTING 2. VENDOR ADDRESS-1: 1624 FOOTHILL BLVD 3. VENDOR ADDRESS-2: SUITE 34 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 91042 7. VENDOR CONTACT: CHARLES JOHANSSEN 8. VENDOR PHONE: (818) 555-4321 ENTER VENDOR NAME aber VENDOR NUMBER: 01176 1. VENDOR NAME: ABERCROMBIE AND OTHERS 2. VENDOR ADDRESS-1: 1234 45TH ST. 3. VENDOR ADDRESS-2: SUITE 17 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 92345 7. VENDOR CONTACT: 8. VENDOR PHONE: (213) 555-6543 ENTER VENDOR NAME b VENDOR NUMBER: 00003 1. VENDOR NAME: CHARLES SMITH AND SONS 2. VENDOR ADDRESS-1: 1435 SOUTH STREET 3. VENDOR ADDRESS-2: 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 90064 7. VENDOR CONTACT: MARTHA HARRISON 8. VENDOR PHONE: (213) 555-4432 ENTER VENDOR NAME
ANALYSIS: This program follows the pattern of vndinq01.cbl and the inquire logic of vndmnt03.cbl, but instead of asking the user for the vendor number, it asks the user for the vendor name.
The user is allowed to enter a partial value--"ABER" for ABERCROMBIE, for example--and the program attempts to locate a record that contains a name that is close to that value.
For each name entered by the user, the program attempts to START the file using that value, and if the start is successful, the next record in the file is read. It is possible for a user to enter a name that is beyond the end of the file, such as "ZZZZZZ", so a VENDOR-FILE-AT-END flag is used to trap entries that do not allow a record to be found in the file.
In this version of inquire, the user enters a vendor name of spaces to signal end of entry; anything else is converted to uppercase and then used by the program. At lines 008400 and 008700, ENTER-VENDOR-NAME ACCEPT-VENDOR-NAME takes care of this simple field-entry routine.
The loop control and loop start at line 005400 in 005400 INQUIRE-BY-NAME. This routine starts by getting a valid record (GET-EXISTING-RECORD) and then performing the main loop, INQUIRE-RECORDS, until the user enters a vendor name of spaces (VENDOR-NAME = SPACES).
The main loop itself at 005900 displays all fields; then at the bottom of the loop, line 006100 asks the user for another vendor name to look for by once again performing GET-EXISTING-RECORD.
The GET-EXISTING-RECORD routine at line 006600 is structured as a standard field-entry routine that performs an ACCEPT-EXISTING-KEY and then a RE-ACCEPT-EXISTING-KEY until VENDOR-FILE-AT-END NOT = "Y". This logic is used to force the user to enter a vendor name that is not at the end of the file.
At line 007100, ACCEPT-EXISTING-KEY initializes the vendor record and then gets the user entry of the name to look up. If the name is not spaces, an attempt is made to READ-FIRST-VENDOR-RECORD, which will START the file using the entered vendor name and then try to read the next record in the file. If this causes VENDOR-FILE-AT-END = "Y", then back at line 006800, the program will RE-ACCEPT-EXISTING-KEY until VENDOR-FILE-AT-END NOT = "Y".
The RE-ACCEPT-EXISTING-KEY routine at line 007700 displays an error message and then tries again to ACCEPT-EXISTING-KEY.
The READ-FIRST-VENDOR-RECORD routine at line 015100 is identical to that used in Listing 17.20, vnbynbm01.cbl, and it sets the VENDOR-FILE-AT-END flag if a record cannot be found.
The remainder of the program is used to display the fields in the record, and you are familiar with this type of logic. Code, compile, and run vninnm01.cbl, and use it to look up records in your vendor file.
A flaw in vninnm01.cbl makes it awkward for the user. In the following output example, the user wants to look up ABERCROMBIE AND OTHERS and enters "ab". In the sample file, two vendors start with "AB", and ABC PRINTING appears before ABERCROMBIE AND OTHERS in the file in alternate key order. The user's entry retrieves ABC PRINTING, and the user must enter "aber" to zero in on the record that is wanted:
OUTPUT:
ENTER VENDOR NAME ab VENDOR NUMBER: 00002 1. VENDOR NAME: ABC PRINTING 2. VENDOR ADDRESS-1: 1624 FOOTHILL BLVD 3. VENDOR ADDRESS-2: SUITE 34 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 91042 7. VENDOR CONTACT: CHARLES JOHANSSEN 8. VENDOR PHONE: (818) 555-4321 ENTER VENDOR NAME aber VENDOR NUMBER: 01176 1. VENDOR NAME: ABERCROMBIE AND OTHERS 2. VENDOR ADDRESS-1: 1234 45TH ST. 3. VENDOR ADDRESS-2: SUITE 17 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 92345 7. VENDOR CONTACT: 8. VENDOR PHONE: (213) 555-6543 ENTER VENDOR NAME
This can become a headache in a large file with many names that are close to one another, and it can be impossible to deal with if two vendors have the same name. In the following sample output, the vendor file contains two firms named ABC PRINTING--one in Los Angeles and one in Pomona:
OUTPUT:
VENDOR NUMBER: 00002 1. VENDOR NAME: ABC PRINTING 2. VENDOR ADDRESS-1: 1624 FOOTHILL BLVD 3. VENDOR ADDRESS-2: SUITE 34 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 91042 7. VENDOR CONTACT: CHARLES JOHANSSEN 8. VENDOR PHONE: (818) 555-4321 VENDOR NUMBER: 00067 1. VENDOR NAME: ABC PRINTING 2. VENDOR ADDRESS-1: 1606 SOUTH 7TH 3. VENDOR ADDRESS-2: 4. VENDOR CITY: POMONA 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 90404 7. VENDOR CONTACT: HARRIET NELSON 8. VENDOR PHONE: (815) 555-2020
The user needs the phone number for the vendor in Pomona but does not know the vendor number. This is a good time to use inquiry by vendor name. However, the next output sample indicates that, in spite of repeated attempts to enter more and more of the company name, vninnm01.cbl always returns the first vendor.
This problem has to do with the way records are stored by alternate key. If an alternate key allows duplicates, and two or more records actually do have the same key value, which one is first? Usually, it is the one that was added to the file first. Sometimes it is the record with the lowest primary index key value. No matter which record is considered to be "first" in the file, vninnm01.cbl will not let you go to the next record:
OUTPUT:
ENTER VENDOR NAME abc VENDOR NUMBER: 00002 1. VENDOR NAME: ABC PRINTING 2. VENDOR ADDRESS-1: 1624 FOOTHILL BLVD 3. VENDOR ADDRESS-2: SUITE 34 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 91042 7. VENDOR CONTACT: CHARLES JOHANSSEN 8. VENDOR PHONE: (818) 555-4321 ENTER VENDOR NAME abc print VENDOR NUMBER: 00002 1. VENDOR NAME: ABC PRINTING 2. VENDOR ADDRESS-1: 1624 FOOTHILL BLVD 3. VENDOR ADDRESS-2: SUITE 34 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 91042 7. VENDOR CONTACT: CHARLES JOHANSSEN 8. VENDOR PHONE: (818) 555-4321 ENTER VENDOR NAME abc printing VENDOR NUMBER: 00002 1. VENDOR NAME: ABC PRINTING 2. VENDOR ADDRESS-1: 1624 FOOTHILL BLVD 3. VENDOR ADDRESS-2: SUITE 34 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 91042 7. VENDOR CONTACT: CHARLES JOHANSSEN 8. VENDOR PHONE: (818) 555-4321 ENTER VENDOR NAME
Listing 17.22 is vninnm02.cbl, and it solves the problem.
000100 IDENTIFICATION DIVISION. 000200 PROGRAM-ID. VNINNM02. 000300*-------------------------------- 000400* Inquire for the Vendor File 000500* using vendor name. 000600*-------------------------------- 000700 ENVIRONMENT DIVISION. 000800 INPUT-OUTPUT SECTION. 000900 FILE-CONTROL. 001000 001100 COPY "SLVND02.CBL". 001200 001300 COPY "SLSTATE.CBL". 001400 001500 DATA DIVISION. 001600 FILE SECTION. 001700 001800 COPY "FDVND04.CBL". 001900 002000 COPY "FDSTATE.CBL". 002100 002200 WORKING-STORAGE SECTION. 002300 002400 77 VENDOR-FILE-AT-END PIC X. 002500 77 STATE-RECORD-FOUND PIC X. 002600 002700 77 SEE-NEXT-RECORD PIC X. 002800 002900 77 VENDOR-NAME-FIELD PIC X(30). 003000 003100 COPY "WSCASE01.CBL". 003200 003300 PROCEDURE DIVISION. 003400 PROGRAM-BEGIN. 003500 PERFORM OPENING-PROCEDURE. 003600 PERFORM MAIN-PROCESS. 003700 PERFORM CLOSING-PROCEDURE. 003800 003900 PROGRAM-DONE. 004000 STOP RUN. 004100 004200 OPENING-PROCEDURE. 004300 OPEN I-O VENDOR-FILE. 004400 OPEN I-O STATE-FILE. 004500 004600 CLOSING-PROCEDURE. 004700 CLOSE VENDOR-FILE. 004800 CLOSE STATE-FILE. 004900 005000 MAIN-PROCESS. 005100 PERFORM INQUIRE-BY-NAME. 005200*-------------------------------- 005300* INQUIRE 005400*-------------------------------- 005500 INQUIRE-BY-NAME. 005600 PERFORM GET-EXISTING-RECORD. 005700 PERFORM INQUIRE-RECORDS 005800 UNTIL VENDOR-NAME = SPACES. 005900 006000 INQUIRE-RECORDS. 006100 PERFORM SHOW-THIS-RECORD. 006200 PERFORM SHOW-NEXT-RECORD 006300 UNTIL SEE-NEXT-RECORD = "N" OR 006400 VENDOR-FILE-AT-END = "Y". 006500 006600 PERFORM GET-EXISTING-RECORD. 006700 006800 006900*-------------------------------- 007000* Show records one by one 007100*-------------------------------- 007200 SHOW-THIS-RECORD. 007300 PERFORM DISPLAY-ALL-FIELDS. 007400 PERFORM GET-SEE-NEXT-RECORD. 007500 007600 SHOW-NEXT-RECORD. 007700 PERFORM READ-NEXT-VENDOR-RECORD. 007800 IF VENDOR-FILE-AT-END NOT = "Y" 007900 PERFORM SHOW-THIS-RECORD. 008000 008100*-------------------------------- 008200* Get valid record logic 008300*-------------------------------- 008400 GET-EXISTING-RECORD. 008500 PERFORM ACCEPT-EXISTING-KEY. 008600 PERFORM RE-ACCEPT-EXISTING-KEY 008700 UNTIL VENDOR-FILE-AT-END NOT = "Y". 008800 008900 ACCEPT-EXISTING-KEY. 009000 PERFORM INIT-FOR-KEY-ENTRY. 009100 PERFORM ENTER-VENDOR-NAME. 009200 IF VENDOR-NAME NOT = SPACES 009300 PERFORM READ-FIRST-VENDOR-RECORD. 009400 009500 RE-ACCEPT-EXISTING-KEY. 009600 DISPLAY "RECORD NOT FOUND" 009700 PERFORM ACCEPT-EXISTING-KEY. 009800 009900*-------------------------------- 010000* Field Entry logic 010100*-------------------------------- 010200 ENTER-VENDOR-NAME. 010300 PERFORM ACCEPT-VENDOR-NAME. 010400 010500 ACCEPT-VENDOR-NAME. 010600 DISPLAY "ENTER VENDOR NAME". 010700 ACCEPT VENDOR-NAME. 010800 INSPECT VENDOR-NAME 010900 CONVERTING LOWER-ALPHA 011000 TO UPPER-ALPHA. 011100 011200 GET-SEE-NEXT-RECORD. 011300 PERFORM ACCEPT-SEE-NEXT-RECORD. 011400 PERFORM RE-ACCEPT-SEE-NEXT-RECORD 011500 UNTIL SEE-NEXT-RECORD = "Y" OR "N". 011600 011700 ACCEPT-SEE-NEXT-RECORD. 011800 DISPLAY "DISPLAY NEXT RECORD (Y/N)?". 011900 ACCEPT SEE-NEXT-RECORD. 012000 012100 IF SEE-NEXT-RECORD = SPACE 012200 MOVE "Y" TO SEE-NEXT-RECORD. 012300 012400 INSPECT SEE-NEXT-RECORD 012500 CONVERTING LOWER-ALPHA 012600 TO UPPER-ALPHA. 012700 012800 RE-ACCEPT-SEE-NEXT-RECORD. 012900 DISPLAY "MUST ENTER YES OR NO". 013000 PERFORM ACCEPT-SEE-NEXT-RECORD. 013100 013200*-------------------------------- 013300* Display logic 013400*-------------------------------- 013500 DISPLAY-ALL-FIELDS. 013600 DISPLAY " ". 013700 PERFORM DISPLAY-VENDOR-NUMBER. 013800 PERFORM DISPLAY-VENDOR-NAME. 013900 PERFORM DISPLAY-VENDOR-ADDRESS-1. 014000 PERFORM DISPLAY-VENDOR-ADDRESS-2. 014100 PERFORM DISPLAY-VENDOR-CITY. 014200 PERFORM DISPLAY-VENDOR-STATE. 014300 PERFORM DISPLAY-VENDOR-ZIP. 014400 PERFORM DISPLAY-VENDOR-CONTACT. 014500 PERFORM DISPLAY-VENDOR-PHONE. 014600 DISPLAY " ". 014700 014800 DISPLAY-VENDOR-NUMBER. 014900 DISPLAY " VENDOR NUMBER: " VENDOR-NUMBER. 015000 015100 DISPLAY-VENDOR-NAME. 015200 DISPLAY "1. VENDOR NAME: " VENDOR-NAME. 015300 015400 DISPLAY-VENDOR-ADDRESS-1. 015500 DISPLAY "2. VENDOR ADDRESS-1: " VENDOR-ADDRESS-1. 015600 015700 DISPLAY-VENDOR-ADDRESS-2. 015800 DISPLAY "3. VENDOR ADDRESS-2: " VENDOR-ADDRESS-2. 015900 016000 DISPLAY-VENDOR-CITY. 016100 DISPLAY "4. VENDOR CITY: " VENDOR-CITY. 016200 016300 DISPLAY-VENDOR-STATE. 016400 MOVE VENDOR-STATE TO STATE-CODE. 016500 PERFORM READ-STATE-RECORD. 016600 IF STATE-RECORD-FOUND = "N" 016700 MOVE "**Not found**" TO STATE-NAME. 016800 DISPLAY "5. VENDOR STATE: " 016900 VENDOR-STATE " " 017000 STATE-NAME. 017100 017200 DISPLAY-VENDOR-ZIP. 017300 DISPLAY "6. VENDOR ZIP: " VENDOR-ZIP. 017400 017500 DISPLAY-VENDOR-CONTACT. 017600 DISPLAY "7. VENDOR CONTACT: " VENDOR-CONTACT. 017700 017800 DISPLAY-VENDOR-PHONE. 017900 DISPLAY "8. VENDOR PHONE: " VENDOR-PHONE. 018000 018100*-------------------------------- 018200* File Related Routines 018300*-------------------------------- 018400 INIT-FOR-KEY-ENTRY. 018500 MOVE SPACE TO VENDOR-RECORD. 018600 MOVE ZEROES TO VENDOR-NUMBER. 018700 MOVE "N" TO VENDOR-FILE-AT-END. 018800 018900 READ-FIRST-VENDOR-RECORD. 019000 MOVE "N" TO VENDOR-FILE-AT-END. 019100 START VENDOR-FILE 019200 KEY NOT < VENDOR-NAME 019300 INVALID KEY 019400 MOVE "Y" TO VENDOR-FILE-AT-END. 019500 019600 IF VENDOR-FILE-AT-END NOT = "Y" 019700 PERFORM READ-NEXT-VENDOR-RECORD. 019800 019900 READ-NEXT-VENDOR-RECORD. 020000 READ VENDOR-FILE NEXT RECORD 020100 AT END 020200 MOVE "Y" TO VENDOR-FILE-AT-END. 020300 020400 READ-STATE-RECORD. 020500 MOVE "Y" TO STATE-RECORD-FOUND. 020600 READ STATE-FILE RECORD 020700 INVALID KEY 020800 MOVE "N" TO STATE-RECORD-FOUND. 020900
The output from vninnm02.cbl enables the user to step through the file record by record or to skip around, starting with different names:
OUTPUT:
ENTER VENDOR NAME abc VENDOR NUMBER: 00002 1. VENDOR NAME: ABC PRINTING 2. VENDOR ADDRESS-1: 1624 FOOTHILL BLVD 3. VENDOR ADDRESS-2: SUITE 34 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 91042 7. VENDOR CONTACT: CHARLES JOHANSSEN 8. VENDOR PHONE: (818) 555-4321 DISPLAY NEXT RECORD (Y/N)?
(User presses Enter here.)
VENDOR NUMBER: 00067 1. VENDOR NAME: ABC PRINTING 2. VENDOR ADDRESS-1: 1606 SOUTH 7TH 3. VENDOR ADDRESS-2: 4. VENDOR CITY: POMONA 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 90404 7. VENDOR CONTACT: HARRIET NELSON 8. VENDOR PHONE: (815) 555-2020 DISPLAY NEXT RECORD (Y/N)?
(User presses Enter here.)
VENDOR NUMBER: 01176 1. VENDOR NAME: ABERCROMBIE AND OTHERS 2. VENDOR ADDRESS-1: 1234 45TH ST. 3. VENDOR ADDRESS-2: SUITE 17 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 92345 7. VENDOR CONTACT: 8. VENDOR PHONE: (213) 555-6543 DISPLAY NEXT RECORD (Y/N)? n ENTER VENDOR NAME z VENDOR NUMBER: 01440 1. VENDOR NAME: ZINZINDORFF INC. 2. VENDOR ADDRESS-1: 1604 7TH ST 3. VENDOR ADDRESS-2: 4. VENDOR CITY: LOS ANGELES 5. VENDOR STATE: CA CALIFORNIA 6. VENDOR ZIP: 90404 7. VENDOR CONTACT: 8. VENDOR PHONE: (213) 555-7234 DISPLAY NEXT RECORD (Y/N)?
ANALYSIS: This program is similar to vninnm01.cbl, but it enables the user to choose the option of looking at the next record after the selected record is displayed.
The differences in the two programs start at line 006000, INQUIRE-RECORDS, in vninnm02.cbl. Rather than displaying all fields and then asking the user for another vendor name, the loop is changed to SHOW-THIS-RECORD and then SHOW-NEXT-RECORD until SEE-NEXT-RECORD = "N" or VENDOR-FILE-AT-END = "Y". The SEE-NEXT-RECORD variable is a yes/no field entered by the user to indicate whether to display the next record. It is defined at line 002700.
At line 007200, the SHOW-THIS-RECORD routine displays all fields and then asks the user whether the next record is wanted. This answer is returned to INQUIRE-RECORDS at line 006200, and if the user has indicated Y by entering the value or simply pressing Enter, the SHOW-NEXT-RECORD routine is performed as a loop.
The SHOW-NEXT-RECORD routine at line 007600 tries to read the next record in the vendor file. If it is successful, it performs SHOW-THIS-RECORD, which displays all fields, and once again asks the user whether the next record is wanted. This loop continues until the user answers N or the read-next takes him or her to the end of the file.
The GET-SEE-NEXT-RECORD routine at line 011200 is a standard field-entry routine. In this case, the user can enter a space, but it is converted to "Y" at lines 012100 and 012200. This gives the user the convenience of pressing Enter to see the next record rather than having to enter a "Y" explicitly. If the user enters something, it must be "Y" or "N" (or the lowercase versions).
The GET-SEE-NEXT-RECORD loop continues until the end of the file is reached, whereupon the user once again is asked for a vendor name.
Code, compile, and run vninnm02.cbl. If you want to, use vndmnt03.cbl to add a vendor with the same name as an existing vendor in the file. You can use vninnm02.cbl to view this record.
Although an indexed file must have a unique primary key, it is possible to put other keys in the file. These do not need to be unique and can be arranged to return records in a different order than the primary key. Today, you learned these basics:
018900 MOVE "LINCOLN" TO VENDOR-NAME. 019000 START VENDOR-FILE 019100 KEY NOT < VENDOR-NAME 019200 INVALID KEY 019300 MOVE "Y" TO VENDOR-FILE-AT-END. 019400 019500 IF VENDOR-FILE-AT-END NOT = "Y" 019600 PERFORM READ-NEXT-VENDOR-RECORD. 019700 019800 READ-NEXT-VENDOR-RECORD. 019900 READ VENDOR-FILE NEXT RECORD 020000 AT END 020100 MOVE "Y" TO VENDOR-FILE-AT-END.
000400 SELECT PART-FILE 000500 ASSIGN TO "PARTS" 000600 ORGANIZATION IS INDEXED 000700 RECORD KEY IS PART-NUMBER 000800 ALTERNATE KEY IS PART-VENDOR WITH DUPLICATES 000900 ALTERNATE KEY IS PART-DEPARTMENT WITH DUPLICATES 001000 ALTERNATE KEY IS PART-VENDOR-NUMBER 001100 ACCESS MODE IS DYNAMIC. 001200
000000 FD CUSTOMER-FILE 000000 LABEL RECORDS ARE STANDARD. 001000 01 CUSTOMER-RECORD. 001100 05 CUSTOMER-NUMBER PIC 9(5). 001200 05 CUSTOMER-NAME PIC X(20). 001300 05 CUSTOMER-ADDRESS-1 PIC X(20). 001400 05 CUSTOMER-ADDRESS-2 PIC X(20). 001500 05 CUSTOMER-ZIP PIC 9(5). 001600 05 CUSTOMER-PHONE. 001700 10 CUSTOMER-AREA-CODE PIC 9(3). 001800 10 CUSTOMER-PREFIX PIC 9(3). 001900 10 CUSTOMER-PHONE-NO PIC 9(4).
© Copyright, Macmillan Computer Publishing. All rights reserved.