Michael Coughlan
Page 29
With Record-KeyC in one buffer (TF) and Record-KeyA in the other (MF), the key field values are compared.
When the transaction is greater than the master (as is the case here), the condition indicates that the position where the transaction record must be inserted has not yet been reached, so the MF record is written to the NMF. Because the MF record in the buffer has been dealt with (consumed), you read the MF to get a new record. This is the record: Record-KeyB.
When the key values are compared, the transaction key is still greater the master, so this record too is written to the NMF and another is read from the MF. This is the record: Record-KeyG.
Now you have reached the point in the program captured by Figure 10-5. This time, the key value in the TF is less than that of the MF, so the transaction record is written to the NMF. Because the record in the TF buffer has been consumed, a new record is read into the buffer, and the process continues until both files end.
To simplify the template, the condition where the key values are equal has been omitted. If this condition occurs, then a transaction error has occurred, because for record-matching purposes, the key values must be unique.
If you examine the algorithm provided, you might be puzzled that there appears to be no code to write out the remaining records to the NMF when one file ends before the other. The explanation for this lies in the end-of-file condition name associated with each file. These might be described as in Example 10-2.
220
Chapter 10 ■ proCessing sequential Files
Example 10-2. Partial Record Descriptions for the Transaction and Master Files
FD TransactionFile
01 TFRec.
88 EndTF VALUE HIGH-VALUES.
02 TFKey PIC X(?).
etc
FD MasterFile
01 MFRec.
88 EndMF VALUE HIGH-VALUES.
02 MFKey PIC X(?).
etc
When the end of either file is encountered, its associated condition name is set to true; this has the side effect of filling its record area (including its key field) with HIGH-VALUES (the highest possible character value). Subsequent key comparisons cause the remaining records to be written to the NMF. For instance, from the test data in Figure 10-1, it is clear that the TF will end first. When the EndTF condition name is set to true, TFkey contains HIGH-VALUES. In the key comparison, TFKey is greater than MFKey, and this results in the master record being written to the NMF. If the MF
ends first, MFKey is filled with HIGH-VALUES, and the key comparisons then causes the remaining transaction records to be written to the NMF.
Updating Records in an Ordered Sequential File
The template for updating records in an ordered sequential file is shown in Figure 10-6. The diagram captures the program action at the point where Record-KeyH has been read into the TF record buffer and the MF record buffer.
Both records are combined to produce the updated record Record-KeyH+, which is then sent to the NMF.
221
Chapter 10 ■ proCessing sequential Files
Figure 10-6. Updating records in an ordered sequential file
When you apply an update to the MF, you combine the records from the TF and the MF because the transaction record only consists of the key field and the field(s) to be updated. For instance, in a stock-file update, the update record in the TF might contain the fields shown in Example 10-3, whereas the MF might contain those shown in Example 10-4.
Example 10-3. Fields in the Update Record of a Transaction File
FD TransactionFile.
01 TFRec.
02 StockId-TF PIC X(?).
02 QtyInStock-TF PIC 9(?).
Example 10-4. Fields in the Record of a Stock Master File
FD StockMasterFile.
01 StockMFRec.
02 StockId-MF PIC X(?).
02 Description-MF PIC X(?).
02 ManfId-MF PIC X(?).
02 ReorderLevel-MF PIC 9(?).
02 ReorderQty-MF PIC 9(?).
02 QtyInStock-MF PIC 9(?).
222
Chapter 10 ■ proCessing sequential Files
The template in Figure 10-6 does not check for the error condition where the record to be updated does not exist in the MF. This condition is detected when the value in TFKey is less than that in MFKey. You can test this yourself by including the record Record-KeyD in the transaction file and then applying the transactions manually.
Deleting Records from an Ordered Sequential File
Figure 10-7 shows the template for deleting records from an ordered sequential file. The diagram captures the action just after Record-KeyK has been read into the MF record buffer. When the keys are equal, you have found the MF record to be deleted. So what action do you take to delete it? No action! You just don’t send it to the NMF. Because both the transaction record and the master record have been consumed, you need to get the next record from each file.
Figure 10-7. Deleting records from an ordered sequential file
When I discussed how to update an ordered sequential file, I noted that the transaction record contained fewer fields than the MF record. The delete operation takes this even further. To delete a record, the transaction record only needs the key field.
As before, the template does not check for the error condition where the record to be deleted does not exist in the MF. Just like the update operation, this condition is detected when the value in TFKey is less than that in MFKey. You can test this yourself by adding the record Record-KeyC to the records in the TF and then applying the transactions manually.
223
Chapter 10 ■ proCessing sequential Files
The File-Update Problem: Simplified
The previous section showed how various types of updates can be applied to an ordered sequential file. But you considered each of these types of updates in isolation. The TF consisted of records of only one type; it contained a batch of deletions, or a batch of insertions, or a batch of updates. In reality, all these different kinds of transaction records would be gathered together into one transaction file. Having multiple record types in the transaction file is good for processing efficiency, but it considerably complicates the update logic.
The problem of how to update an ordered sequential file is known as the file-update problem. The file-update problem is much more difficult than it appears on the surface and has been the subject of some research. Of particular interest is Barry Dwyer’s paper “One More Time—How to Update a Master File.3” The algorithm described in his paper is implemented in Listing 10-2.
This section considers a simplified version of updating a file containing multiple record types. In this version, multiple updates for a particular master record are allowed, but an insertion record cannot be followed by any other operation for the same record. That restriction reveals the further levels of complexity of the file-update problem.
Obviously, in a stock file, there might be a number of stock movements (additions and subtractions from stock) for a particular stock item. But in some cases, there might be an insertion for a particular stock item followed by stock movements and other updates for that item. In such a situation, the order in which the transactions are applied is important, because obviously you want to insert the record before you apply updates to it. These and other issues considerably complicate the file-update problem.
Updating a Stock File: Problem Specification
To explore some of the complexities of applying transactions of different types to a master file, consider the following problem specification.
A stock file holds details of gadgets sold by Gadget Shop (GadgetShop.Com). It is a sequential file sorted on ascending GadgetId. Each record in the file has the following description:
Field
Type
Length
Value
GadgetId
9
6
000001–999999
GadgetName
X
30
-
QtyInStock
9
4
0000–9999
Price
9
6
0000.00–9999.99
To update the stock file, a number of different kinds of update records have been gathered together into a sequential transaction file.
The records in transaction file have seen sorted into ascending GadgetId order. Within GadgetId, the
transactions are sorted by the order in which they were submitted. There are three different types of transaction records: insertion records to add a new line of stock, deletion records to delete a line of stock, and price-change records change the Price of a line of stock. Obviously, you could also have stock-movement records to add and subtract inventory from the QtyInStock field, but that would needlessly complicate this example.
Because there are three different types of records in the transaction file, you need to have three different record descriptions. But as you discovered in Chapter 8, when a file contains multiple types of records, you must have some way of identifying which record type has been read into the record buffer. To distinguish one type of record from 3Barry Dwyer. 1981. One more time — how to update a master file. Commun. ACM 24, 1 (January 1981), 3-8. DOI=10.1145/358527.358534
http://doi.acm.org/10.1145/358527.358534.
224
Chapter 10 ■ proCessing sequential Files
another, a special field called a type code is inserted into each transaction record. In the transaction file used to update Gadget Shop’s stock file, a type code value of 1 is used to represent insertions, 2 represents deletions, and 3 represents a price change. The records in the transaction file have the following descriptions:
Insertion Record
Field
Type
Length
Value
TypeCode
9
1
1
GadgetId
9
6
000001-999999
GadgetName
X
30
-
QtyInStock
9
4
0000–9999
Price
9
6
0000.00–9999.99
Deletion Record
Field
Type
Length
Value
TypeCode
9
1
2
GadgetId
9
6
000001–999999
Price Change Record
Field
Type
Length
Value
TypeCode
9
1
3
GadgetId
9
6
000001–999999
Price
9
6
0000.00–9999.99
Because there are three different types of records in the file, you must have three record descriptions in the FD entry for the transaction file (see Example 10-5).
Example 10-5. Record Descriptions for the Transaction File
FD TransactionFile.
01 InsertionRec.
02 TypeCode PIC 9.
02 GadgetId PIC 9(6).
02 GadgetName PIC X(30).
02 QtyInStock PIC 9(4).
02 Price PIC 9(4)V99.
01 DeletionRec.
02 TypeCode PIC 9.
02 GadgetID PIC 9(6).
01 PriceChangeRec.
02 TypeCode PIC 9.
02 GadgetID PIC 9(6).
02 Price PIC 9(4)V99.
225
Chapter 10 ■ proCessing sequential Files
Buffer Implications of Multiple Record Types
You discovered in Chapter 8 that when a file contains multiple record types, a record declaration (starting with a 01 level number) must be created for each type of record. But even though there are different types of records in the file, and there are separate record declarations for each record type, only a single record buffer is created for the file.
All the record descriptions map on to this area of storage, which is the size of the largest record. Figure 10-8 shows the mapping of the transaction records on to the record buffer. All the identifiers in all the mapped records are current/active at the same time, but only one set of identifiers makes sense for the particular record in the buffer.
In Figure 10-8, the record in the buffer is an insertion record (TypeCode = 1), so even though you could execute the statement MOVE Price TO PrnPrice, it wouldn’t make sense to do so. Because there is an insertion record in the buffer, Price has the value “Ice Cr.”
Figure 10-8. Schematic showing the mapping of records on to the record buffer
When you examine the record descriptions in Example 10-5 and the record schematic in Figure 10-8, you may notice that both TypeCode and GadgetId occur in all three record descriptions. You may wonder if is it permitted to use the same data name in different records. And if it is permitted, how can the data name be referenced uniquely?
Although it is legal to use the same data name in different records (but not in the same group item), in order to uniquely identify the record you want, you must qualify it with the record or group name. For instance, you can refer to the GadgetId in PriceChangeRec by using the form GadgetId OF PriceChangeRec.
But even though it is legal to declare GadgetId in all the records, and even though you must declare the storage for GadgetId in all the records, you don’t actually need to use the name GadgetId in all the records. Because all the records map on to the same area of storage, it does not matter which GadgetId you refer to—they all access the same value in the record. So no matter which record is in the buffer, a statement that refers to GadgetId OF InsertRec will still access the correct value.
The same logic applies to the TypeCode. The TypeCode is in the same place in all three record types, so it doesn’t matter which one you use—they all access the same area of memory. When an area of storage must be declared, but you don’t care what name you give it, you don’t have to make up a dummy name. You use the special name FILLER.
Example 10-6 shows a revised version of the three record descriptions. In this version, only the items that have to be named are given data names. The record schematic for this revised version is shown in Figure 10-9.
226
Chapter 10 ■ proCessing sequential Files
Example 10-6. Revised Record Descriptions
FD TransactionFile.
01 InsertionRec.
02 TypeCode PIC 9.
02 GadgetId PIC 9(6).
02 GadgetName PIC X(30).
02 QtyInStock PIC 9(4).
02 Price PIC 9(4)V99.
01 DeletionRec.
02 FILLER PIC 9(7).
01 PriceChangeRec.
02 FILLER PIC 9(7).
02 Price PIC 9(4)V99.
Figure 10-9. Mapping of transaction records on to the record buffer
File Update Program
The program required to apply the transaction file to the gadget stock file is shown in Listing 10-3.
Listing 10-3. File Update—Insert not followed by updates to inserted record
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing10-3.
AUTHOR. Michael Coughlan
* Applies the transactions ordered on ascending GadgetId-TF to the
* MasterStockFile ordered on ascending GadgetId-MF.
* Assumption: Insert not followed by updates to inserted record
* Multiple updates per master record permitted
227
Chapter 10 ■ proCessing sequential Files
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT MasterStockFile ASSIGN TO "Listing10-3Master.dat"
&
nbsp; ORGANIZATION IS LINE SEQUENTIAL.
SELECT NewStockFile ASSIGN TO "Listing10-3NewMast.dat"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT TransactionFile ASSIGN TO "Listing10-3Trans.dat"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD MasterStockFile.
01 MasterStockRec.
88 EndOfMasterFile VALUE HIGH-VALUES.
02 GadgetId-MF PIC 9(6).
02 GadgetName-MF PIC X(30).
02 QtyInStock-MF PIC 9(4).
02 Price-MF PIC 9(4)V99.
FD NewStockFile.
01 NewStockRec.
02 GadgetId-NSF PIC 9(6).
02 GadgetName-NSF PIC X(30).
02 QtyInStock-NSF PIC 9(4).
02 Price-NSF PIC 9(4)V99.
FD TransactionFile.
01 InsertionRec.
88 EndOfTransFile VALUE HIGH-VALUES.
02 TypeCode-TF PIC 9.
88 Insertion VALUE 1.
88 Deletion VALUE 2.
88 UpdatePrice VALUE 3.
02 GadgetId-TF PIC 9(6).
02 GadgetName-IR PIC X(30).
02 QtyInStock-IR PIC 9(4).
02 Price-IR PIC 9(4)V99.
01 DeletionRec.
02 FILLER PIC 9(7).
01 PriceChangeRec.
02 FILLER PIC 9(7).
02 Price-PCR PIC 9(4)V99.
WORKING-STORAGE SECTION.
01 ErrorMessage.
02 PrnGadgetId PIC 9(6).
02 FILLER PIC XXX VALUE " - ".
228
Chapter 10 ■ proCessing sequential Files
02 FILLER PIC X(45).
88 InsertError VALUE "Insert Error - Record already exists".
88 DeleteError VALUE "Delete Error - No such record in Master".
88 PriceUpdateError VALUE "Price Update Error - No such record in Master".
PROCEDURE DIVISION.
Begin.
OPEN INPUT MasterStockFile
OPEN INPUT TransactionFile
OPEN OUTPUT NewStockFile
PERFORM ReadMasterFile