| Introduction
|
Aims
| This tutorial covers a number of topics including; COBOL print files, multiple record-type files, variable length records, and run-time file name assignment.
|
Objectives
| By the end of this unit you should -
|
Prerequisites
| Introduction to COBOL Declaring data in COBOL Basic Procedure Division Commands Selection Constructs Iteration Constructs Introduction to Sequential files Processing Sequential files
|
| Multiple record-type files
|
Introduction
| In the tutorial - Processing Sequential Files - the transaction files used as examples only contained batched records of a single type. For instance, the transaction file contained either a batch of deletions, or a batch of insertions or a batch of updates. In a real environment, transactions of this sort would normally be collected together into one single transaction file. This section demonstrates how files, which contain a number of different types of record, may be declared and used.
|
Implications of multiple record types
| A transaction file which contains insertion, deletion and update records, raises some interesting problems. Gathering all these types of transactions into a single file implies that the file will contain records of different types (i.e. records with different structures) and this may give rise to records of different lengths. A deletion record only needs the key field StudentId (7 characters), while an insertion requires the whole record (30 characters, and an update may be somewhere between these two depending on which fields, and how many of them, are being updated.
|
Declaring a multiple record-type file |
To describe these different record types we have to use more than one record description in the file's FD entry. Because record descriptions always begin with level 01, we must provide a 01 level for each record type in the file. In the example below, the declarations required for a transaction containing insert, deletion and update records are given. In this example, the update transaction is intended to update the course code, with a new course code.
What is not obvious from this description is that COBOL still continues to create just a single ‘record buffer’ for the file! And this ‘record buffer’ is only able to store a single record at a time!
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Multiple record-types - one record buffer |
When a file contains multiple record types, a record declaration (starting with a 01 level number) must be created for each type of record. Even though there are different types of record 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 declarations map on to this area of storage, which is the size of the largest record, and all the identifiers, in all the mapped records, are current/active at the same time. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Implications of record mappings |
The buffer, in the illustration above, currently contains an insert record. But even though the record is an insert record, it is still possible to refer to the NewCourseCode, because all the identifiers, in all the mapped records, are available for use (are active). Of course, it doesn't make any sense to refer to NewCourseCode because the record is not an update record. For instance, in this case, the statement DISPLAY NewCourseCode would display "COUG" instead of an actual course code. When a record is read into a shared buffer, it is the programmers responsibility to discover what type of record has been read into the buffer and then, only to refer to the fields that make sense for that type of record. For instance, if an update record has been read into the buffer, then it only makes sense to refer to StudentId and NewCourseCode. We can still access the values in StudentName or DateOfBirth but they will not be meaningful. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The type-code. |
Looking at the record above, you might wonder how the programmer can discover what type of record had been read into the buffer. Sometimes we can discover what type of record is in the buffer by examining the record and looking for characteristics, such as a particular value or data type, that are unique to that type of record. But generally, we cannot reliably establish the type of record in the buffer, by simply examining it. To allow us to distinguish between record types, a special data-item, which identifies the transaction type, is usually inserted into each transaction, . This data-item is usually called the transaction type-code. It is usually the first data-item in the transaction record and is usually one character in size, but it can be placed anywhere in the record, be of any size, and be any type of character. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The revised record descriptions. |
In the program fragment below, the revised record descriptions are shown. These record descriptions now include a one character field, which stores the type-code inserted into each transaction record to indicate the transaction type. Obviously the transaction file (TRANS.DAT) must must also be altered so that its actual records contain the type-code.
When you examine the record descriptions above a question may occur to you. TransCode occurs in all the record descriptions - is this legal and how can I refer to the one in DeleteRec? The answer is - yes! It is legal to use the same identifier in different records (but not in the same record); but in order to uniquely identify the one you want, you must qualify it with the record name. So we can refer to the TransCode in the delete record by using the form TransCode OF DeleteRec. For instance, we might MOVE TransCode OF DeleteRec TO PrnCode. But even though it is legal to declare TransCode in all the records, and even though we must declare the storage for TransCode in all the records, we don't actually need to use the name TransCode in all the records. Since all the records map on to the same area of storage, it does not matter which TransCode we refer to - they all access the same value in the record. So if an update record is in the buffer, a statement referring to TransCode OF InsertRec, will still access the correct value. The same logic applies to the StudentId. The StudentId is in the same place in all three record types, so it doesn't matter which one we use - they all access the same area of memory. When an area of storage must be declared but we don't care what name we give it, we use the special name - FILLER. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Using FILLER in the transaction records. |
In the program fragment below, the final record descriptions are shown. TransCode and StudentId have the same description and are in the same location in all three records, so they have been explicitly defined only in the InsertionRec. In the other records, the area occupied by the two items is named - FILLER.
The record schematic for this new record is shown below. Notice how the TransCode and StudentId in the InsertRec map on to the same area of storage as the FILLERs in the other two record types.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
COBOL print files | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Introduction
|
In a business-programming environment, the ability to print reports is an important property for a programming language. COBOL allows programmers to write to the printer, either directly or through an intermediate print file. COBOL treats the printer as a serial file, but uses a special variant of the WRITE verb to control the placement of lines on the page.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Setting up a print file
|
All data coming from, or going to, the peripherals must pass through a file buffer declared in the File Section. The file buffer is associated with the physical device by means of a Select and Assign clause. In the case of a print file, the Select and Assign may assign the print file to an actual physical printing device or, more likely, to a file which is sent to the printer later. In the diagram below one print file is assigned directly to a printer while the other is assigned to a file.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Declaring print lines |
A report is made up of groups of printed lines of different types. There may be heading lines at the beginning of the report, and at the top of each page; there will be detail lines, where the main information of the report is printed; there may be footing lines at the bottom of each page, or at the end of the report. When we set up a print file we create an FD for the file and a print record for each type of print line that will appear on the report. For instance, let's suppose we want to write a program to print a Student Details Report which shows the StudentName, StudentId, Gender and CourseCode of each student in the students file. In the Student Details Report there will be;
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Problems multiple print records. |
There is a problem with the different kinds of print record we must have in a print file. As we have seen in the previous section, if a file is declared as having multiple record types, all the records map on to the same physical area of storage. This doesn't cause any difficulties if the file is an input file, because only one type of record at a time can be in the buffer. But as we can see from the print line declarations above, the information in many print lines is static - set up at compile time - so all the records have to be in the buffer at the same time. Obviously this is impossible. In fact to prevent the creation of print records in the FILE SECTION, there is a COBOL rule which states that, in the FILE SECTION, the VALUE clause can only be used with Condition Names (i.e. it cannot be used to give an initial value to an item). If the print records cannot be set up in the file's FD entry in the FILE SECTION. How do we set up a print file?
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Setting up a print file |
To set up a print file, the print line records are declared in the WORKING-STORAGE SECTION; and in the FILE SECTION, a record the size of the largest print-line record is declared in the file's FD entry. A line is printed by moving it from the WORKING-STORAGE SECTION, to the PrintLine record in the FILE SECTION, and that record is then written to the print file. This is shown graphically in the illustration below.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The WRITE format revisited.
|
The WRITE syntax for writing to print files is more complicated than that used for writing in ordinary Sequential files because it must contain entries to allow us to control the vertical placement of the print lines. The revised write syntax is shown below.
WRITE notes The PAGE option writes a form feed to the print file or printer. MnemonicName refers to a vendor-specific page control command. It is defined in the SPECIAL-NAMES paragraph. When writing to print files the WRITE..FROM option is generally used because the print records are described in the Working Storage Section . When the WRITE..FROM option is used, the data is moved from the source area into the record buffer before the contents of the record buffer are written to the file. The WRITE..FROM is the equivalent of a MOVE SourceItem TO RecordBuffer statement followed by a WRITE RecordBuffer statement. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Bringing it all together. |
The example program below implements the Student Details Report specified above;
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Variable length records | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Introduction |
COBOL programs normally process fixed-length records but sometimes files contain records of different lengths. For instance, the transaction file introduced in the first section, contains three different types of fixed-length record and an ordinary text file contains records whose size is differs from record to record. This section demonstrates how files, containing variable-length records, may be declared and processed.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
FD entries for variable length records |
The File Description (FD) entry was introduced in the first tutorial on Sequential files. But the entry shown in that tutorial was very simple; it consisted of the letters FD followed by the filename. An FD entry can be more complicated than this, and can have a large number of subordinate clauses (see your vendor manual or help files). Among these clauses is the RECORD IS VARYING IN SIZE clause. The RECORD IS VARYING IN SIZE clause allows us to specify that a file contains variable length records. The syntax diagram for this clause is shown below.
Notes The RecordSize#i in the DEPENDING ON phase must be an elementary unsigned integer data-item declared in the WORKING-STORAGE SECTION. Examples FD TransFile RECORD IS VARYING IN SIZE FROM 8 TO 31 CHARACTERS. FD Stringfile RECORD IS VARYING IN SIZE FROM 1 TO 80 CHARACTERS DEPENDING ON StringSize.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
How variable-length records, declared with the DEPENDING ON phrase, work. |
When a record is read from a file, defined with the RECORD IS VARYING IN SIZE.. DEPENDING ON phrase, the size of the record read into the buffer is moved into the data-item RecordSize#i (see the example program below). To write to a file, defined with the RECORD IS VARYING IN SIZE.. DEPENDING ON phrase, the size of the record to be written must first be moved to RecordSize#i data-item, and then the WRITE statement must be executed.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Example program |
The example program below introduces and number of new techniques and concepts;
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Copyright NoticeThese COBOL course materials are the copyright property of Michael Coughlan. All rights reserved. No part of these course materials may be reproduced in any form or by any means - graphic, electronic, mechanical, photocopying, printing, recording, taping or stored in an information storage and retrieval system - without the written permission of the author. (c) Michael Coughlan Last updated : March
1999 mailto:michael.coughlan@ul.ie | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||