This chapter introduces the COBOL Report Writer. In a series of increasingly complex programs, you learn how to use the Report Writer to create control-break-based report programs. By examining these programs, you are gradually introduced to the new verbs, clauses, sections and concepts of the Report Writer. You see how to use the RD entry in the REPORT SECTION to specify control-break items and define the basic layout of the page. The chapter explores report groups and how to create report groups linked to the control-break items specified in the report’s RD entry. You learn how to use the SUM clause for subtotaling and rolling forward. The final program introduces declaratives and how to use them to extend the capabilities of the Report Writer. Once you’ve seen the capabilities of the Report Writer through the example programs, the chapter explores the verbs, clauses, and concepts of the Report Writer more formally.
Declaratives can be used to extend the capabilities of the Report Writer, but you can also use them to define exception-handling procedures for files. The final section explains how to create declaratives for file error handling.
Report Writer
Producing reports is an important aspect of business programming. Nowadays, reports may consist of rows and columns of figures and be supported by summary information in the form of a variety of charts and graphs. In the past, reports consisted solely of printed figures. You’ve probably seen such reports in old films, where a management person is poring over page after page of green-lined, fan-fold computer printout.
Although producing reports is important, unfortunately the report programs produced using standard COBOL print files (see Chapter 8) are often tedious to code. Report programs are long, achieving correct placement of horizontal and vertical print items is laborious, and the programs frequently consist of repetitions of the tasks and techniques (such as control-break processing) used in other report programs. In recognition of the importance of reports in the business domain, and to simplify the task of writing report programs, COBOL provides the Report Writer.
Like indexed files, the COBOL Report Writer used to be one of the jewels in COBOL’s crown. But today, just as relational databases have eroded the importance of indexed files, so off-the-shelf packages such as Crystal Reports with its array of charts and graphs have put COBOL’s Report Writer in the shade. Nevertheless, although summary information in the form of charts and graphs is very useful, there is still a need for printed reports; and you can learn a lot from a close acquaintance with the Report Writer.
I start by showing you an example of a report produced by the Report Writer. Then, through a series of increasingly complex report programs, you learn how to create the program that produced that report. The final example program takes the complexity one stage further.
Example Report: Solace Solar Solutions
This report shows the sales made by agents selling solar power products in each of the 50 American states. You see the program specification and the report, and then I follow up with a discussion that highlights the report’s features. After discussing the report, I show you the PROCEDURE DIVISION code that produced the report.
Problem Specification
Solace Solar Solutions is a company that sells solar power products through its sales agents all over the United States. Sales agents are paid a base salary (which is different from state to state) and a commission of 8% on the value of the products they sell.
The monthly report shows the value of the individual sales and the total sales made by each Solace sales agent. The total sales made for the state and the base salary for the state are also shown. The report is printed on ascending sales agent number within ascending state name.
The report is based on a sequential sales file, which contains details of each sale made in the country. The sales file is ordered on ascending sales agent number within ascending state number. Each record of the sales file has the following description:
Example Report
The first page of the example report is shown in Example 18-1. For ease of reference, I have attached line numbers to the report.
Example 18-1. Solace Solar Solutions Example Report: First Page
01 Solace Solar Solutions
02 Sales Agent - Sales and Salary Report Monthly Report
03
04 State Agent Value
05 Name Number Of Sales
06 Alabama 38 $9,325.14
07 $11,839.19
08 $19,102.61
09 Sales for sales agent 38 = $40,266.94
10
11
12 Alabama 73 $4,503.71
13 $11,659.87
14 $19,540.19
15 Sales for sales agent 73 = $35,703.77
16
17 Total sales for Alabama $75,970.71
18 Base salary for Alabama $1,149.00
19 ----------------------------------------------------------
20
21
22 Alaska 55 $18,981.84
23 $3,065.97
24 $10,686.92
25 Sales for sales agent 55 = $32,734.73
26
27
28 Alaska 89 $11,187.72
29 $14,145.82
30 Sales for sales agent 89 = $25,333.54
31
32
33 Alaska 104 $18,005.42
34 $17,614.20
35 Sales for sales agent 104 = $35,619.62
36
37 Total sales for Alaska $93,687.89
38 Base salary for Alaska $1,536.00
39 ----------------------------------------------------------
40
41
42 Arizona 23 $4,237.72
43
44
45
46
47
48
49 Programmer - Michael Coughlan Page : 1
Report Writer Tasks
To get a feel for what the Report Writer can do, let’s examine in some detail what it has to do to produce this report:
Accumulate all the sales values, and print them as a final total at the end of the report (not shown on the example page).
Report Writer PROCEDURE DIVISION
If you had to create the Solace Solar Solutions sales report using the approach shown in Chapter 8 (that is, using a control-break program and the WRITE verb), you would probably write a program that had a PROCEDURE DIVISION with more than 100 lines of code. It is interesting to discover that the Report Writer can do all this work in just the 10 COBOL statements shown in Example 18-2.
Example 18-2. PROCEDURE DIVISION That Produces the Sales Report
PROCEDURE DIVISION.
Begin.
OPEN INPUT SalesFile.
OPEN OUTPUT PrintFile.
READ SalesFile
AT END SET EndOfFile TO TRUE
END-READ.
INITIATE SolaceSalesReport.
PERFORM PrintSalaryReport
UNTIL EndOfFile.
TERMINATE SolaceSalesReport.
CLOSE SalesFile, PrintFile.
STOP RUN.
PrintSalaryReport.
GENERATE DetailLine.
READ SalesFile
AT END SET EndOfFile TO TRUE
END-READ.
So Much Work, So Little Code
How can so much work be done in so little PROCEDURE DIVISION code? How does the Report Writer know that page headings or page footers are required? If you wrote a program to print this report using WRITE statements, you would need a control-break program with a PERFORM UNTIL StateNum NOT EQUAL TO PrevStateNum loop to process each state and an inner loop PERFORM UNTIL SalesAgentNum NOT EQUAL TO PrevSalesAgentNum to process the sales for each sales agent. Without those loops, how does the Report Writer know it is time to print the sales agent totals or the state totals, and how does it accumulate those totals in the first place?
To achieve so much in so little PROCEDURE DIVISION code, the Report Writer uses a declarative approach to programming rather than the imperative (procedural) approach familiar to most programmers. In imperative programming, you tell the computer how to do what you want done. In declarative programming, you tell the computer what you would like done, and the computer works out how to do it. When you use the Report Writer, you declare what to print when a page heading, page footer, sales agent total, state total, or final total is required, and the Report Writer works out when to print these items. In keeping with the adage that “there is no such thing as a free lunch,” the PROCEDURE DIVISION of a Report Writer program is short because most of the work is done in the (greatly expanded) DATA DIVISION.
How the Report Writer Works
The Report Writer works by recognizing that many reports take (more or less) the same shape. There may be headings at the beginning of the report and footers at the end. There may be headings at the top of each page and footers at the bottom. Headings or footers may need to be printed whenever there is a control break (that is, when the value in a specified field changes, such as when the sales agent number or state number changes in Example 18-1). In addition, the detail lines that display the information summarized in control-break totals also need to be printed.
The Report Writer calls these different report items report groups. Reports are organized around report groups. The Report Writer recognizes the seven types of report group shown in Example 18-3; the indentation shows their relative importance/order of execution.
Example 18-3. Report Group Types
REPORT HEADING or RH group
- printed once at the beginning of the report
PAGE HEADING or PH group
- printed at the top of each page
CONTROL HEADING or CH group
- printed at the beginning of each control break
DETAIL or DE group
- printed each time the GENERATE statement is executed
CONTROL FOOTING or CF group
- printed at the end of each control break
PAGE FOOTING or PF group
- printed at the bottom of each page
REPORT FOOTING or RF group
- printed once at the end of the report.
For each report, there must be a Report Description (RD) entry in the REPORT SECTION of the DATA DIVISION that fully describes the report. The report groups that describe the report are defined as records in the RD entries. Most groups are defined once for each report, but control groups are defined for each control-break item. For instance, in the example program, control footings are defined on SalesAgentNum, StateNum, and FINAL. FINAL is a special control group that is invoked before or after the normal control groups (before if CONTROL HEADING FINAL is used, and after if CONTROL FOOTING FINAL is used).
Ordinary control groups are defined on a control-break data item. The Report Writer monitors the contents of the designated data item, and when the value changes, a control break is automatically initiated. When the control break is initiated, the CONTROL FOOTING group of the breaking item (if there is one) and the CONTROL HEADING group of the next item are printed.
Writing a report program consists of a number of tedious tasks such as keeping track of the line count to ensure that page headings or footers are printed when required, or simply moving data values into their corresponding items in the print line. In addition, when you write a report according to a program specification, you often have to adhere to the report layout specified in a print layout form such as that shown in Figure 18-1. When you have to adhere to such a form, it can be tricky to get the vertical and horizontal placement of printed items correct. Counting characters to figure out what size to make each of the fields that define a print line is tedious and time consuming.
Figure 18-1. Print layout form showing the layout required for a report
The Report Writer makes it easier to write report programs by
Writing a Report Program
Let’s see how to write a report program using the Report Writer. I start with a simplified version of the program that produced the report in Example 18-1. Succeeding examples add to it to demonstrate additional Report Writer facilities. The final example demonstrates even more than the report in Example 18-1.
Modifying the Specification
This first example program creates a report program that does the following:
The first page of the report produced by this program is shown in Example 18-4 (line numbers have been added). The program that produces the report is shown in Listing 18-1.
Example 18-4. Simplified Version of the Report Showing Only Sales Agent Totals
01 Solace Solar Solutions
02 Sales Agent - Sales and Salary Report Monthly Report
03
04 State Agent Value
05 Name Number Of Sales
06 Alabama 38 $9,325.14
07 Alabama 38 $11,839.19
08 Alabama 38 $19,102.61
09 Sales for sales agent 38 = $40,266.94
10
11
12 Alabama 73 $4,503.71
13 Alabama 73 $11,659.87
14 Alabama 73 $19,540.19
15 Sales for sales agent 73 = $35,703.77
16 ----------------------------------------------------------
17
18
19 Alaska 55 $18,981.84
20 Alaska 55 $3,065.97
21 Alaska 55 $10,686.92
22 Sales for sales agent 55 = $32,734.73
23
24
25 Alaska 89 $11,187.72
26 Alaska 89 $14,145.82
27 Sales for sales agent 89 = $25,333.54
28
29
30 Alaska 104 $18,005.42
31 Alaska 104 $17,614.20
32 Sales for sales agent 104 = $35,619.62
33 ----------------------------------------------------------
34
35
36 Arizona 23 $4,237.72
37 Arizona 23 $13,315.00
38 Sales for sales agent 23 = $17,552.72
39
40
41 Arizona 90 $2,078.93
42 Arizona 90 $17,228.88
43 Arizona 90 $8,929.96
44 Sales for sales agent 90 = $28,237.77
45 ----------------------------------------------------------
46
47
48
49 Programmer - Michael Coughlan Page : 1
Listing 18-1. Simplified Report Program
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing18-1.
AUTHOR. Michael Coughlan.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SalesFile ASSIGN TO "Listing18-1-Sales.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT PrintFile ASSIGN TO "Listing18-1.Rpt".
DATA DIVISION.
FILE SECTION.
FD SalesFile.
01 SalesRecord.
88 EndOfFile VALUE HIGH-VALUES.
02 StateNum PIC 99.
02 SalesAgentNum PIC 999.
02 ValueOfSale PIC 9(5)V99.
FD PrintFile
REPORT IS SolaceSalesReport.
WORKING-STORAGE SECTION.
01 StateNameTable.
02 StateNameValues.
03 FILLER PIC X(14) VALUE "Alabama".
03 FILLER PIC X(14) VALUE "Alaska".
03 FILLER PIC X(14) VALUE "Arizona".
03 FILLER PIC X(14) VALUE "Arkansas".
03 FILLER PIC X(14) VALUE "California".
03 FILLER PIC X(14) VALUE "Colorado".
03 FILLER PIC X(14) VALUE "Connecticut".
03 FILLER PIC X(14) VALUE "Delaware".
03 FILLER PIC X(14) VALUE "Florida".
03 FILLER PIC X(14) VALUE "Georgia".
03 FILLER PIC X(14) VALUE "Hawaii".
03 FILLER PIC X(14) VALUE "Idaho".
03 FILLER PIC X(14) VALUE "Illinois".
03 FILLER PIC X(14) VALUE "Indiana".
03 FILLER PIC X(14) VALUE "Iowa".
03 FILLER PIC X(14) VALUE "Kansas".
03 FILLER PIC X(14) VALUE "Kentucky".
03 FILLER PIC X(14) VALUE "Louisiana".
03 FILLER PIC X(14) VALUE "Maine".
03 FILLER PIC X(14) VALUE "Maryland".
03 FILLER PIC X(14) VALUE "Massachusetts".
03 FILLER PIC X(14) VALUE "Michigan".
03 FILLER PIC X(14) VALUE "Minnesota".
03 FILLER PIC X(14) VALUE "Mississippi".
03 FILLER PIC X(14) VALUE "Missouri".
03 FILLER PIC X(14) VALUE "Montana".
03 FILLER PIC X(14) VALUE "Nebraska".
03 FILLER PIC X(14) VALUE "Nevada".
03 FILLER PIC X(14) VALUE "New Hampshire".
03 FILLER PIC X(14) VALUE "New Jersey".
03 FILLER PIC X(14) VALUE "New Mexico".
03 FILLER PIC X(14) VALUE "New York".
03 FILLER PIC X(14) VALUE "North Carolina".
03 FILLER PIC X(14) VALUE "North Dakota".
03 FILLER PIC X(14) VALUE "Ohio".
03 FILLER PIC X(14) VALUE "Oklahoma".
03 FILLER PIC X(14) VALUE "Oregon".
03 FILLER PIC X(14) VALUE "Pennsylvania".
03 FILLER PIC X(14) VALUE "Rhode Island".
03 FILLER PIC X(14) VALUE "South Carolina".
03 FILLER PIC X(14) VALUE "South Dakota".
03 FILLER PIC X(14) VALUE "Tennessee".
03 FILLER PIC X(14) VALUE "Texas".
03 FILLER PIC X(14) VALUE "Utah".
03 FILLER PIC X(14) VALUE "Vermont".
03 FILLER PIC X(14) VALUE "Virginia".
03 FILLER PIC X(14) VALUE "Washington".
03 FILLER PIC X(14) VALUE "West Virginia".
03 FILLER PIC X(14) VALUE "Wisconsin".
03 FILLER PIC X(14) VALUE "Wyoming".
02 FILLER REDEFINES StateNameValues.
03 State OCCURS 50 TIMES.
04 StateName PIC X(14).
REPORT SECTION.
RD SolaceSalesReport
CONTROLS ARE StateNum
SalesAgentNum
PAGE LIMIT IS 54
FIRST DETAIL 3
LAST DETAIL 46
FOOTING 48.
01 TYPE IS REPORT HEADING NEXT GROUP PlUS 1.
02 LINE 1.
03 COLUMN 20 PIC X(32)
VALUE "Solace Solar Solutions".
02 LINE 2.
03 COLUMN 6 PIC X(51)
VALUE "Sales Agent - Sales and Salary Report Monthly Report".
01 TYPE IS PAGE HEADING.
02 LINE IS PLUS 1.
03 COLUMN 2 PIC X(5) VALUE "State".
03 COLUMN 16 PIC X(5) VALUE "Agent".
03 COLUMN 32 PIC X(8) VALUE "Value".
02 LINE IS PLUS 1.
03 COLUMN 2 PIC X(4) VALUE "Name".
03 COLUMN 16 PIC X(6) VALUE "Number".
03 COLUMN 31 PIC X(8) VALUE "Of Sales".
01 DetailLine TYPE IS DETAIL.
02 LINE IS PLUS 1.
03 COLUMN 1 PIC X(14)
SOURCE StateName(StateNum).
03 COLUMN 17 PIC ZZ9
SOURCE SalesAgentNum.
03 COLUMN 30 PIC $$$,$$$.99 SOURCE ValueOfSale.
01 SalesAgentGrp
TYPE IS CONTROL FOOTING SalesAgentNum NEXT GROUP PLUS 2.
02 LINE IS PLUS 1.
03 COLUMN 15 PIC X(21) VALUE "Sales for sales agent".
03 COLUMN 37 PIC ZZ9 SOURCE SalesAgentNum.
03 COLUMN 43 PIC X VALUE "=".
03 TotalAgentSales COLUMN 45 PIC $$$$$,$$$.99 SUM ValueOfSale.
01 StateGrp TYPE IS CONTROL FOOTING StateNum NEXT GROUP PLUS 2.
02 LINE IS PLUS 1.
03 COLUMN 1 PIC X(58) VALUE ALL "-".
01 TYPE IS PAGE FOOTING.
02 LINE IS 49.
03 COLUMN 1 PIC X(29) VALUE "Programmer - Michael Coughlan".
03 COLUMN 55 PIC X(6) VALUE "Page :".
03 COLUMN 62 PIC ZZ9 SOURCE PAGE-COUNTER.
PROCEDURE DIVISION.
Begin.
OPEN INPUT SalesFile.
OPEN OUTPUT PrintFile.
READ SalesFile
AT END SET EndOfFile TO TRUE
END-READ.
INITIATE SolaceSalesReport.
PERFORM PrintSalaryReport
UNTIL EndOfFile.
TERMINATE SolaceSalesReport.
CLOSE SalesFile, PrintFile.
STOP RUN.
PrintSalaryReport.
GENERATE DetailLine.
READ SalesFile
AT END SET EndOfFile TO TRUE
END-READ.
The first thing to note is that the PROCEDURE DIVISION for this program is the same as for the program that produced the report in Example 18-1. This is your first indication that most of the work is being done in the DATA DIVISION. As I add complexity to the program in the succeeding examples, eventually I have to make some changes to the PROCEDURE DIVISION code.
The second thing to note is that just like an ordinary print file, a Report Writer file must have a SELECT and ASSIGN clause in the ENVIRONMENT DIVISION and an FD entry in the DATA DIVISION. But look at the FD entry. Instead of a record description, you have a REPORT IS SolaceSalesReport entry. This entry tells you that the Report Writer is being used and that this particular report is called SolaceSalesReport. This entry links the PrintFile with the report described in the REPORT SECTION. That is the next thing to note; when you use the Report Writer, you describe the report in the REPORT SECTION.
The first entry in the REPORT SECTION is the RD entry, which is followed by the name of the report. This is the same name you use in the REPORT IS entry in the FD entry of the PrintFile. The RD entry has a number of clauses. The first is the CONTROLS ARE clause, which allows you to identify the control-break item(s) that the Report Writer must monitor in order to detect a control break. These entries usually identify fields in an input file, but they don’t have to. The remaining RD clauses specify information about the page, such as the size of the page, the first line where a detail line may be printed, and the line after which the footer may be printed.
The remaining entries identify the required report groups. Each report group is a record and must start with a 01 level number. As noted in Example 18-3, there are seven possible types of report groups, and the first entry in the report group must specify the type of the group. Listing 18-1 has the following report groups:
Report Groups
Let’s look at some of the entries in these report groups in more detail. The REPORT HEADING group is of interest because it demonstrates absolute position using the LINE clause. It also demonstrates the COLUMN clause, which you use to specify the horizontal placement of the material to be printed. The final item of interest in this group is the NEXT GROUP PLUS clause, which specifies that the next group will start one line down from this group. Although, as you see with the PAGE HEADING group, you can specify vertical placement using a relative reference rather than an absolute line number, that is not always sufficient for all your positioning needs. Sometimes you require a combination of the NEXT GROUP PLUS and the LINE IS PLUS clauses.
You might think that the PAGE HEADING group would also use absolute positioning, but in this example, the page headings are not printed on the same line on every page. On the first page, they are printed after the report heading lines; but on the other pages, they are printed on the first line. For this reason, LINE IS PLUS relative positioning is used for this group. Because the other groups, except the PAGE FOOTING group, are also printed on different lines on the page, they also use LINE IS PLUS relative positioning.
The main clause of interest in the DETAIL report group is the SOURCE clause. This clause specifies that the data for this print item is to come from some source data item. This is how the Report Writer gets values for the state name (from the table), the sales agent number, and the value of the sale.
SalesAgentGrp is a CONTROL FOOTING group. It is printed whenever there is a control break on SalesAgentNum. When you create a CONTROL group, you have to associate the group with a control item mentioned in the RD..CONTROLS ARE phrase. This is how the Report Write associates a particular control-break item with a CONTROL HEADING or FOOTING group. At the moment, this group only prints a line of hyphens; but the next program uses it to accumulate and print the total sales agent sales.
The final group to consider is the PAGE FOOTING group. The item of interest in this group is PAGE-COUNTER, which is identified as the source of the page number printed in this footer. PAGE-COUNTER is a special Report Writer register that automatically keeps a count of the pages printed.
PROCEDURE DIVISION Notes
Now that you have seen the role played by the DATA DIVISIONentries in producing the report, you need to know how the report is driven from the PROCEDURE DIVISION. The Report Writer introduces three new verbs: INITIATE, GENERATE, and TERMINATE.
When the INITIATE verb is executed, all the heading groups, such as REPORT HEADING and the first PAGE HEADING, are produced. All the system registers, such as PAGE-COUNTER, are set to their starting values.
When the TERMINATE verb is executed, all the relevant FOOTING groups, such as REPORT FOOTING and the last PAGE FOOTING, are produced.
The report is driven by the GENERATE verb. GENERATE is normally associated either with the DETAIL group (as it is in this example) or with the report name. When GENERATE is associated with a DETAIL group, each time the GENERATE statement is executed, the DETAIL group is printed. Obviously this makes sense only if each time GENERATE executes, the DETAIL group is fed new data. In this program, the new data is provided by reading the sales file.
Adding Features to the Report Program
Let’s add some features to the Solace Sales Report program. Let’s change the program so that the report now shows the total sales for the sales agent, total sales for the state, and a final total for the country. The report should also show the base salary paid to sales agents in each state. To do this, the state table has to be modified to include the salary information. One final thing needs to change. If you look at the report in Example 18-4, you see that each line that prints a sales value also prints the state name and the sales agent number. This looks unsightly. The state name and the sales agent number should be suppressed after their first occurrence. Instead of this
04 State Agent Value
05 Name Number Of Sales
06 Alabama 38 $9,325.14
07 Alabama 38 $11,839.19
08 Alabama 38 $19,102.61
09 Sales for sales agent 38 = $40,266.94
the report should print this:
04 State Agent Value
05 Name Number Of Sales
06 Alabama 38 $9,325.14
07 $11,839.19
08 $19,102.61
09 Sales for sales agent 38 = $40,266.94
You probably have realized by now that these specification changes are satisfied by the report shown in Example 18-1. Listing 18-2 is the program that produced that report.
Listing 18-2. Program to Create a Report with Sales Totals
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing18-2.
AUTHOR. Michael Coughlan.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SalesFile ASSIGN TO "Listing18-2-Sales.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT PrintFile ASSIGN TO "Listing18-2.Rpt".
DATA DIVISION.
FILE SECTION.
FD SalesFile.
01 SalesRecord.
88 EndOfFile VALUE HIGH-VALUES.
02 StateNum PIC 99.
02 SalesAgentNum PIC 999.
02 ValueOfSale PIC 9(5)V99.
FD PrintFile
REPORT IS SolaceSalesReport.
WORKING-STORAGE SECTION.
01 StateNameTable.
02 StateNameValues.
03 FILLER PIC X(18) VALUE "1149Alabama".
03 FILLER PIC X(18) VALUE "1536Alaska".
03 FILLER PIC X(18) VALUE "1284Arizona".
03 FILLER PIC X(18) VALUE "1064Arkansas".
03 FILLER PIC X(18) VALUE "1459California".
03 FILLER PIC X(18) VALUE "1508Colorado".
03 FILLER PIC X(18) VALUE "1742Connecticut".
03 FILLER PIC X(18) VALUE "1450Delaware".
03 FILLER PIC X(18) VALUE "1328Florida".
03 FILLER PIC X(18) VALUE "1257Georgia".
03 FILLER PIC X(18) VALUE "1444Hawaii".
03 FILLER PIC X(18) VALUE "1126Idaho".
03 FILLER PIC X(18) VALUE "1439Illinois".
03 FILLER PIC X(18) VALUE "1203Indiana".
03 FILLER PIC X(18) VALUE "1267Iowa".
03 FILLER PIC X(18) VALUE "1295Kansas".
03 FILLER PIC X(18) VALUE "1126Kentucky".
03 FILLER PIC X(18) VALUE "1155Louisiana".
03 FILLER PIC X(18) VALUE "1269Maine".
03 FILLER PIC X(18) VALUE "1839Maryland".
03 FILLER PIC X(18) VALUE "1698Massachusetts".
03 FILLER PIC X(18) VALUE "1257Michigan".
03 FILLER PIC X(18) VALUE "1479Minnesota".
03 FILLER PIC X(18) VALUE "0999Mississippi".
03 FILLER PIC X(18) VALUE "1236Missouri".
03 FILLER PIC X(18) VALUE "1192Montana".
03 FILLER PIC X(18) VALUE "1261Nebraska".
03 FILLER PIC X(18) VALUE "1379Nevada".
03 FILLER PIC X(18) VALUE "1571New Hampshire".
03 FILLER PIC X(18) VALUE "1743New Jersey".
03 FILLER PIC X(18) VALUE "1148New Mexico".
03 FILLER PIC X(18) VALUE "1547New York".
03 FILLER PIC X(18) VALUE "1237North Carolina".
03 FILLER PIC X(18) VALUE "1290North Dakota".
03 FILLER PIC X(18) VALUE "1256Ohio".
03 FILLER PIC X(18) VALUE "1155Oklahoma".
03 FILLER PIC X(18) VALUE "1309Oregon".
03 FILLER PIC X(18) VALUE "1352Pennsylvania".
03 FILLER PIC X(18) VALUE "1435Rhode Island".
03 FILLER PIC X(18) VALUE "1172South Carolina".
03 FILLER PIC X(18) VALUE "1206South Dakota".
03 FILLER PIC X(18) VALUE "1186Tennessee".
03 FILLER PIC X(18) VALUE "1244Texas".
03 FILLER PIC X(18) VALUE "1157Utah".
03 FILLER PIC X(18) VALUE "1374Vermont".
03 FILLER PIC X(18) VALUE "1607Virginia".
03 FILLER PIC X(18) VALUE "1487Washington".
03 FILLER PIC X(18) VALUE "1062West Virginia".
03 FILLER PIC X(18) VALUE "1393Wisconsin".
03 FILLER PIC X(18) VALUE "1393Wyoming".
02 FILLER REDEFINES StateNameValues.
03 State OCCURS 50 TIMES.
04 BaseSalary PIC 9(4).
04 StateName PIC X(14).
REPORT SECTION..
RD SolaceSalesReport
CONTROLS AREFINAL
StateNum
SalesAgentNum
PAGE LIMIT IS 54
FIRST DETAIL 3
LAST DETAIL 42
FOOTING 48.
01 TYPE IS REPORT HEADING NEXT GROUP PlUS 1.
02 LINE 1.
03 COLUMN 20 PIC X(32)
VALUE "Solace Solar Solutions".
02 LINE 2.
03 COLUMN 6 PIC X(51)
VALUE "Sales Agent - Sales and Salary Report Monthly Report".
01 TYPE IS PAGE HEADING.
02 LINE IS PLUS 1.
03 COLUMN 2 PIC X(5) VALUE "State".
03 COLUMN 16 PIC X(5) VALUE "Agent".
03 COLUMN 32 PIC X(8) VALUE "Value".
02 LINE IS PLUS 1.
03 COLUMN 2 PIC X(4) VALUE "Name".
03 COLUMN 16 PIC X(6) VALUE "Number".
03 COLUMN 31 PIC X(8) VALUE "Of Sales".
01 DetailLine TYPE IS DETAIL.
02 LINE IS PLUS 1.
03 COLUMN 1 PIC X(14)
SOURCE StateName(StateNum)GROUP INDICATE.
03 COLUMN 17 PIC ZZ9
SOURCE SalesAgentNum GROUP INDICATE.
03 COLUMN 30 PIC $$$,$$$.99 SOURCE ValueOfSale.
01 SalesAgentGrp
TYPE IS CONTROL FOOTING SalesAgentNum NEXT GROUP PLUS 2.
02 LINE IS PLUS 1.
03 COLUMN 15 PIC X(21) VALUE "Sales for sales agent".
03 COLUMN 37 PIC ZZ9 SOURCE SalesAgentNum.
03 COLUMN 43 PIC X VALUE "=".
03 TotalAgentSales COLUMN 45 PIC $$$$$,$$$.99 SUM ValueOfSale.
01 StateGrp TYPE IS CONTROL FOOTING StateNum NEXT GROUP PLUS 2.
02 LINE IS PLUS 2.
03 COLUMN 15 PIC X(15) VALUE "Total sales for".
03 COLUMN 31 PIC X(14) SOURCE StateName(StateNum).
03 TotalStateSales COLUMN 45 PIC $$$$$,$$$.99 SUM TotalAgentSales.
02 LINE IS PLUS 1.
03 COLUMN 15 PIC X(15) VALUE "Base salary for".
03 COLUMN 31 PIC X(14) SOURCE StateName(StateNum).
03 COLUMN 48 PIC $$,$$$.99 SOURCE BaseSalary(StateNum).
02 LINE IS PLUS 1.
03 COLUMN 1 PIC X(58) VALUE ALL "-".
01 TotalSalesGrp TYPE IS CONTROL FOOTING FINAL.
02 LINE IS PLUS 2.
03 COLUMN 15 PIC X(11)
VALUE "Total sales".
03 COLUMN 46 PIC X VALUE "=".
03 COLUMN 48 PIC $$,$$$,$$$.99 SUM TotalStateSales.
01 TYPE IS PAGE FOOTING.
02 LINE IS 49.
03 COLUMN 1 PIC X(29) VALUE "Programmer - Michael Coughlan".
03 COLUMN 55 PIC X(6) VALUE "Page :".
03 COLUMN 62 PIC ZZ9 SOURCE PAGE-COUNTER.
PROCEDURE DIVISION.
Begin.
OPEN INPUT SalesFile.
OPEN OUTPUT PrintFile.
READ SalesFile
AT END SET EndOfFile TO TRUE
END-READ.
INITIATE SolaceSalesReport.
PERFORM PrintSalaryReport
UNTIL EndOfFile.
TERMINATE SolaceSalesReport.
CLOSE SalesFile, PrintFile.
STOP RUN.
PrintSalaryReport.
GENERATE DetailLine.
READ SalesFile
AT END SET EndOfFile TO TRUE
END-READ.
Let’s look at the changes. The major differences between Listing 18-1 and Listing 18-2 are shown in bold. The PROCEDURE DIVISION has not changed. But there is a new control group: in order to print the final total for the country, a CONTROL FOOTING group is required. This control group is controlled by a special control item called FINAL. Note that now the CONTROLS ARE phrase in the report’s RD contains the word FINAL. The FINAL control-break item activates when the report is terminated. You should also take note of the order of the control-break items in the CONTROLS ARE phrase. FINAL is the major control break, StateNum is next in importance, and SalesAgentNum is the least important. A break on a major control item causes a break on all the subordinate control items.
If you examine the report in Example 18-5, you’ll see that now StateName and SalesAgentNum are suppressed after their first occurrence. This is done by specifying the GROUP INDICATE clause for the data item.
Another change to the program was required to accumulate and print the total sales for the sales agent. The Report Writer has three ways of incrementing totals: subtotaling, rolling forward, and crossfooting. All these methods use the SUM clause but target different types of data item. Subtotaling targets data items in the FILE SECTION or the WORKING-STORAGE SECTION. Rolling forward targets data items in a subordinate CONTROL FOOTING group. Crossfooting targets data items in the same group. This example uses subtotaling and rolling forward.
Subtotaling is used in SalesAgentGrp to sum the sales made by the agent. A SUM clause is used that targets the ValueOfSale data item so that every time a GENERATE statement is executed, the current value of ValueOfSale is added to a sum counter. When the control break occurs, the CONTROL FOOTING group activates, and the value accumulated in the sum counter is printed.
There is something else here that you note. As you have no doubt noticed, in the REPORT SECTION you don’t have to follow a level number with a data-item name or even the word FILLER. This saves a lot of unnecessary work. But you can include a name if you want to. In the SalesAgentGrp, I have included the name TotalAgentSales. The reason for naming this item is shown in the StateGrp CONTROL FOOTING group, where it is used as the target of the SUM clause. Every time there is a control break on SalesAgentNum, the current value of TotalAgentSales is added to the sum counter in StateGrp. When there is a control break on StateNum, the accumulated value of the sum counter is printed. This is an example of rolling forward.
Rolling forward is also used with TotalStateSales in StateGrp. TotalStateSales is used as the target of the SUM clause in TotalSalesGrp to sum each state total into a final total. When the TERMINATE statement is executed, the final total is printed.
Adding More Features to the Report Program
In the specification at the start of this section, I mentioned that Solace sales agents are paid a base salary and a commission of 8% on the value of the products they sell. In Listing 18-3, each time the total sales for an agent are printed, the commission they have earned and their total salary (base salary + commission) should also be printed. The first page of the report produced by Listing 18-3 is shown in Example 18-5.
Listing 18-3. Adding the Sales Agent Commission and Salary to the Report
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing18-3.
AUTHOR. Michael Coughlan.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SalesFile ASSIGN TO "Listing18-3-Sales.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT PrintFile ASSIGN TO "Listing18-3.Rpt".
DATA DIVISION.
FILE SECTION.
FD SalesFile.
01 SalesRecord.
88 EndOfFile VALUE HIGH-VALUES.
02 StateNum PIC 99.
02 SalesAgentNum PIC 999.
02 ValueOfSale PIC 9(5)V99.
FD PrintFile
REPORT IS SolaceSalesReport.
WORKING-STORAGE SECTION.
01 StateNameTable.
0 02 StateNameValues.
03 FILLER PIC X(18) VALUE "1149Alabama".
03 FILLER PIC X(18) VALUE "1536Alaska".
03 FILLER PIC X(18) VALUE "1284Arizona".
03 FILLER PIC X(18) VALUE "1064Arkansas".
03 FILLER PIC X(18) VALUE "1459California".
03 FILLER PIC X(18) VALUE "1508Colorado".
03 FILLER PIC X(18) VALUE "1742Connecticut".
03 FILLER PIC X(18) VALUE "1450Delaware".
03 FILLER PIC X(18) VALUE "1328Florida".
03 FILLER PIC X(18) VALUE "1257Georgia".
03 FILLER PIC X(18) VALUE "1444Hawaii".
03 FILLER PIC X(18) VALUE "1126Idaho".
03 FILLER PIC X(18) VALUE "1439Illinois".
03 FILLER PIC X(18) VALUE "1203Indiana".
03 FILLER PIC X(18) VALUE "1267Iowa".
03 FILLER PIC X(18) VALUE "1295Kansas".
03 FILLER PIC X(18) VALUE "1126Kentucky".
03 FILLER PIC X(18) VALUE "1155Louisiana".
03 FILLER PIC X(18) VALUE "1269Maine".
03 FILLER PIC X(18) VALUE "1839Maryland".
03 FILLER PIC X(18) VALUE "1698Massachusetts".
03 FILLER PIC X(18) VALUE "1257Michigan".
03 FILLER PIC X(18) VALUE "1479Minnesota".
03 FILLER PIC X(18) VALUE "0999Mississippi".
03 FILLER PIC X(18) VALUE "1236Missouri".
03 FILLER PIC X(18) VALUE "1192Montana".
03 FILLER PIC X(18) VALUE "1261Nebraska".
03 FILLER PIC X(18) VALUE "1379Nevada".
03 FILLER PIC X(18) VALUE "1571New Hampshire".
03 FILLER PIC X(18) VALUE "1743New Jersey".
03 FILLER PIC X(18) VALUE "1148New Mexico".
03 FILLER PIC X(18) VALUE "1547New York".
03 FILLER PIC X(18) VALUE "1237North Carolina".
03 FILLER PIC X(18) VALUE "1290North Dakota".
03 FILLER PIC X(18) VALUE "1256Ohio".
03 FILLER PIC X(18) VALUE "1155Oklahoma".
03 FILLER PIC X(18) VALUE "1309Oregon".
03 FILLER PIC X(18) VALUE "1352Pennsylvania".
03 FILLER PIC X(18) VALUE "1435Rhode Island".
03 FILLER PIC X(18) VALUE "1172South Carolina".
03 FILLER PIC X(18) VALUE "1206South Dakota".
03 FILLER PIC X(18) VALUE "1186Tennessee".
03 FILLER PIC X(18) VALUE "1244Texas".
03 FILLER PIC X(18) VALUE "1157Utah".
03 FILLER PIC X(18) VALUE "1374Vermont".
03 FILLER PIC X(18) VALUE "1607Virginia".
03 FILLER PIC X(18) VALUE "1487Washington".
03 FILLER PIC X(18) VALUE "1062West Virginia".
03 FILLER PIC X(18) VALUE "1393Wisconsin".
03 FILLER PIC X(18) VALUE "1393Wyoming".
02 FILLER REDEFINES StateNameValues.
03 State OCCURS 50 TIMES.
04 BaseSalary PIC 9(4).
04 StateName PIC X(14).
01 MiscVariables.
02 SalesCommission PIC 9(5)V99.
02 Percentage PIC V99 VALUE .08.
02 FullSalary PIC 9(6)V99.
02 ActualStateNum PIC 99.
REPORT SECTION.
RD SolaceSalesReport
CONTROLS ARE FINAL
StateNum
SalesAgentNum
PAGE LIMIT IS 66
HEADING 1
FIRST DETAIL 6
LAST DETAIL 54
FOOTING 56.
01 TYPE IS PAGE HEADING.
02 LINE 1.
03 COLUMN 20 PIC X(32)
VALUE "Solace Solar Solutions".
02 LINE 2.
03 COLUMN 6 PIC X(51)
VALUE "Sales Agent - Sales and Salary Report Monthly Report".
02 LINE 4.
03 COLUMN 2 PIC X(5) VALUE "State".
03 COLUMN 16 PIC X(5) VALUE "Agent".
03 COLUMN 32 PIC X(8) VALUE "Value".
02 LINE 5.
03 COLUMN 2 PIC X(4) VALUE "Name".
03 COLUMN 16 PIC X(6) VALUE "Number".
03 COLUMN 31 PIC X(8) VALUE "Of Sales".
01 DetailLine TYPE IS DETAIL.
02 LINE IS PLUS 1.
03 COLUMN 1 PIC X(14)
SOURCE StateName(StateNum) GROUP INDICATE.
03 COLUMN 17 PIC 999
SOURCE SalesAgentNum GROUP INDICATE.
03 COLUMN 30 PIC $$$,$$$.99 SOURCE ValueOfSale.
01 SalesAgentGrp
TYPE IS CONTROL FOOTING SalesAgentNum NEXT GROUP PLUS 2.
02 LINE IS PLUS 1.
03 COLUMN 15 PIC X(21) VALUE "Sales for sales agent".
03 COLUMN 37 PIC 999 SOURCE SalesAgentNum.
03 COLUMN 43 PIC X VALUE "=".
03 TotalAgentSales COLUMN 45 PIC $$$$$,$$$.99 SUM ValueOfSale.
02 LINE IS PLUS 1.
03 COLUMN 15 PIC X(19) VALUE "Sales commission is".
03 COLUMN 43 PIC X VALUE "=".
03 COLUMN 45 PIC $$$$$,$$$.99 SOURCE SalesCommission.
02 LINE IS PLUS 1.
03 COLUMN 15 PIC X(22) VALUE "Sales agent salary is".
03 COLUMN 43 PIC X VALUE "=".
03 COLUMN 45 PIC $$$$$,$$$.99 SOURCE FullSalary.
01 StateGrp TYPE IS CONTROL FOOTING StateNum NEXT GROUP PLUS 2.
02 LINE IS PLUS 2.
03 COLUMN 15 PIC X(15) VALUE "Total sales for".
03 COLUMN 31 PIC X(14) SOURCE StateName(StateNum).
03 TotalStateSales COLUMN 45 PIC $$$$$,$$$.99 SUM TotalAgentSales.
02 LINE IS PLUS 1.
03 COLUMN 15 PIC X(15) VALUE "Base salary for".
03 COLUMN 31 PIC X(14) SOURCE StateName(StateNum).
03 COLUMN 48 PIC $$,$$$.99 SOURCE BaseSalary(StateNum).
02 LINE IS PLUS 1.
03 COLUMN 15 PIC X(26)
VALUE "Actual state number is -".
03 COLUMN 42 PIC Z9 SOURCE ActualStateNum.
02 LINE IS PLUS 1.
03 COLUMN 15 PIC X(26)
VALUE "Supplied state number is -".
03 COLUMN 42 PIC Z9 SOURCE StateNum.
02 LINE IS PLUS 1.
03 COLUMN 1 PIC X(58) VALUE ALL "-".
01 TotalSalesGrp TYPE IS CONTROL FOOTING FINAL.
02 LINE IS PLUS 4.
03 COLUMN 15 PIC X(11)
VALUE "Total sales".
03 COLUMN 46 PIC X VALUE "=".
03 COLUMN 48 PIC $$,$$$,$$$.99 SUM TotalStateSales.
01 TYPE IS PAGE FOOTING.
02 LINE IS 58.
03 COLUMN 1 PIC X(29) VALUE "Programmer - Michael Coughlan".
03 COLUMN 55 PIC X(6) VALUE "Page :".
03 COLUMN 62 PIC ZZ9 SOURCE PAGE-COUNTER.
PROCEDURE DIVISION.
DECLARATIVES.
Calc SECTION.
USE BEFORE REPORTING SalesAgentGrp.
Calculate-Salary.
MULTIPLY TotalAgentSales BY Percentage
GIVING SalesCommission ROUNDED
ADD SalesCommission, BaseSalary(StateNum)
GIVING FullSalary.
END DECLARATIVES.
Main SECTION.
Begin.
OPEN INPUT SalesFile
OPEN OUTPUT PrintFile
READ SalesFile
AT END SET EndOfFile TO TRUE
END-READ
INITIATE SolaceSalesReport
PERFORM PrintSalaryReport
UNTIL EndOfFile
TERMINATE SolaceSalesReport
CLOSE SalesFile, PrintFile
STOP RUN.
PrintSalaryReport.
GENERATE DetailLine
READ SalesFile
AT END SET EndOfFile TO TRUE
END-READ
MOVE StateNum TO ActualStateNum.
Example 18-5. Report Showing Commission Earned and Total Salary
Solace Solar Solutions
Sales Agent - Sales and Salary Report Monthly Report
State Agent Value
Name Number Of Sales
Alabama 038 $9,325.14
$11,839.19
$19,102.61
Sales for sales agent 038 = $40,266.94
Sales commission is = $3,221.36
Sales agent salary is = $4,370.36
Alabama 073 $4,503.71
$11,659.87
$19,540.19
Sales for sales agent 073 = $35,703.77
Sales commission is = $2,856.30
Sales agent salary is = $4,005.30
Total sales for Alabama $75,970.71
Base salary for Alabama $1,149.00
Actual state number is - 2
Supplied state number is - 1
----------------------------------------------------------
Alaska 055 $18,981.84
$3,065.97
$10,686.92
Sales for sales agent 055 = $32,734.73
Sales commission is = $2,618.78
Sales agent salary is = $4,154.78
Alaska 089 $11,187.72
$14,145.82
Sales for sales agent 089 = $25,333.54
Sales commission is = $2,026.68
Sales agent salary is = $3,562.68
Alaska 104 $18,005.42
$17,614.20
Sales for sales agent 104 = $35,619.62
Sales commission is = $2,849.57
Sales agent salary is = $4,385.57
Total sales for Alaska $93,687.89
Base salary for Alaska $1,536.00
Actual state number is - 3
Supplied state number is - 2
----------------------------------------------------------
Programmer - Michael Coughlan Page : 1
The major differences between Listing 18-2 and Listing 18-3 are shown in bold. To print the agent commission and total salary, I have added a number of entries to SalesAgentGrp. Note, though, that the sources of these items are data items declared outside the REPORT SECTION. The reason is that these items require calculations beyond what the Report Writer can handle automatically. To calculate these items, you must use declaratives. I discuss declaratives presently; but for now, I want to discuss another issue.
Look at the StateGrp CONTROL FOOTING and in particular at these lines:
03 COLUMN 31 PIC X(14) SOURCE StateName(StateNum).
03 COLUMN 48 PIC $$,$$$.99 SOURCE BaseSalary(StateNum).
Notice anything strange? This footer is printed when there is a control break on StateNum—in other words, when the value of StateNum changes. This means StateNum in the previous lines should refer to the next state and not the one for which the totals have just been accumulated. And yet, if you examine the report, you see that the correct state name and base salary are printed. How can this be? Remember this:
In aCONTROL FOOTINGor in theDECLARATIVES SECTION, when a control data item is referenced, the value supplied is the previous value and not the value that has just caused the control break.
To emphasize this point, I have printed the actual state number value (the one in the record buffer) and the state number supplied by the Report Writer. To get the actual state number, each time a record is read, the StateNum in the record is moved to the ActualStateNum in the WORKING-STORAGE SECTION. This data item is used as a SOURCE when the CONTROL FOOTING is printed.
Report Writer Declaratives
The Report Writer is a wonderful tool if the structure of the required report fits the way the Report Writer does things. But sometimes the structure or requirements of a report are such that the standard Report Writer alone is not sufficient. In these cases, you can use declaratives to extend the functionality of the Report Writer.
The USE BEFORE REPORTING phrase allows code specified in the declaratives to be executed just before the report group mentioned in the USE BEFORE REPORTING phrase is printed. The code in the declaratives extends the functionality of the Report Writer by performing tasks or calculations that the Report Writer cannot do automatically or by selectively stopping a report group from being printed (using the SUPPRESS PRINTING command).
In Listing 18-3, declaratives are used to calculate SalesCommission and FullSalary before SalesAgentGrp is printed.
Report Writer Syntax and Semantics
I have shown you a number of example programs that use the Report Writer. That informal introduction should have given you a good idea of the new verbs and declarations required when you write a Report Writer program. This section deals with the syntax and semantics of Report Writer elements.
ENVIRONMENT DIVISION Entries
Just like ordinary reports, the reports generated by the Report Writer are written to an external device—usually a report file. The ENVIRONMENT DIVISION entries for a report file are the same as those for an ordinary file. The same SELECT and ASSIGN clauses apply. You can either omit the ORGANIZATION phrase as in the example programs, in which case the default of ORGANIZATION IS SEQUENTIAL applies, or you can specify ORGANIZATION IS SEQUENTIAL explicitly, as in the following example:
FILE-CONTROL.
SELECT SalesFile ASSIGN TO "Listing18-4-Sales.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT PrintFile ASSIGN TO "Listing18-4.Rpt"
ORGANIZATION IS SEQUENTIAL.
FILE SECTION Entries
The entries in the ENVIRONMENT DIVISION are the same as those for ordinary print files. But in the FILE SECTION, the normal file description is replaced by the REPORT IS phrase, which points to the RD in the REPORT SECTION. The metalanguage for the phrase is
where ReportName must be the same as the ReportName used in the RD entry. You can see this in Listing 18-3, where the REPORT IS SolaceSalesReport phrase links the PrintFile with the RD in the REPORT SECTION.
Note that before the report can be used, it must be opened for output. For instance, in Listing 18-3, the PrintFile is opened for output before the SolaceSalesReport is generated.
Report Description (RD) Entries
The RD entry in the REPORT SECTION defines the report. There must be a separate RD entry for each report you want to print. The RD entry names the report, specifies the format of the printed page, and identifies the control-break items.
Each RD entry is followed by one or more 01 level-number entries. Each 01 level-number entry identifies a report group and consists of a hierarchical structure similar to a COBOL record. Each report group is a unit consisting of one or more print lines and cannot be split across pages. The metalanguage for the RD is given in Figure 18-2.
Figure 18-2. Metalanguage for the Report Description (RD) entry
Keep the following points in mind:
Report Group Entries
The RD entry specifies the name of the report, identifies the control items, and lays down the basics of how the page is to be formatted. After the RD entry, you specify the report groups to be used in the report. Each report group is represented by a report-group record. As with all record descriptions in COBOL, a report-group record starts with level number 01. The subordinate items in the record describe the report lines and columns in the report group.
Each report group starts with a level 01 report group definition. The metalanguage for the report group definition is given in Figure 18-3.
Figure 18-3. Metalanguage for the report group definition
RD Entry
When you create an RD entry, keep in mind that ReportGroupName is required only when the group
LINE NUMBER Clause
When you use the LINE NUMBER clause, keep the following in mind:
NEXT GROUP Clause
When you use the NEXT GROUP clause, keep the following things in mind:
The TYPE Clause
The TYPE clause specifies the type of the report group. The type of the report group governs when and where it is printed in the report (for instance, a REPORT HEADING group is printed only once: at the beginning of the report).
When you use the TYPE clause, keep the following things in mind:
Report Group Lines
The subordinate items in a report-group record describe the report lines and columns in the report group. There are two formats for defining items subordinate to the report-group record. The first is usually used to define the lines of the report group, and the second defines and positions the elementary print items.
Defining the Print Lines
Print lines in a report group are usually defined using the metalanguage given in Figure 18-4. This format is used to specify the vertical placement of a print line, and it is always followed by subordinate items that specify the columns where the data items are to be printed.
Figure 18-4. Metalanguage for vertical print line positioning
As shown in the metalanguage, the level number is from 2 to 48, inclusive. If ReportLineName is used, its only purpose is to qualify a SUM counter reference.
Defining the Elementary Print Items
The elementary print items in the print line of a report group are described using the metalanguage shown in Figure 18-5. As you can see, the normal data-description clauses such as PIC, USAGE, SIGN, JUSTIFIED, BLANK WHEN ZERO, and VALUE may be applied when describing an elementary print item. The Report Writer provides a number of additional clauses that may also be used with these items.
Figure 18-5. Metalanguage to define elementary report items
SumCounterName can only be referenced if the entry uses the SUM clause to define a sum counter.
The COLUMN NUMBER Clause
When you use the COLUMN NUMBER clause, keep the following things in mind:
The GROUP INDICATE Clause
The GROUP INDICATE clause can only appear in a DETAIL report group. It is used to specify that a print item should be printed only on the first occurrence of its report group after a control break or page advance. For instance, in Listing 18-3, the state name and sales agent number are suppressed after their first occurrence. As a reminder, I have repeated the DETAIL group declaration here:
01 DetailLine TYPE IS DETAIL.
02 LINE IS PLUS 1.
03 COLUMN 1 PIC X(14)
SOURCE StateName(StateNum) GROUP INDICATE.
03 COLUMN 17 PIC 999
SOURCE SalesAgentNum GROUP INDICATE.
03 COLUMN 30 PIC $$$,$$$.99 SOURCE ValueOfSale.
The SOURCE Clause
The SOURCE clause is used to identify a data item that contains the value to be used when the print item is printed. For instance, the SOURCE ValueOfSale clause in the previous example specifies that the value of the item to be printed in column 30 is to be found in the data item ValueOfSale.
The SUM Clause
The SUM clause is used both to establish a sum counter and to name the data items to be summed. A SUM clause can appear only in the description of a CONTROL FOOTING report group. Statements in the PROCEDURE DIVISION can be used to alter the contents of the sum counters.
You can do three forms of summing in the Report Writer:
When the SUM clause is used with a data item declared in the FILE or WORKING-STORAGE SECTION, then each time a GENERATE is executed, the value to be summed is added to the sum counter. If there is more than one DETAIL group in the report, the SUM..UPON option allows you to select which sum counter to total. For instance, if the report contains two DETAIL groups—one called DetailLine and the other called AlternateDetailLine—you can use SUM..UPON to specify that subtotaling is to be done only each time a GENERATE AlternateDetailLine is executed.
Rolling Forward
When the SUM clause is used with a data item representing the sum counter of another CONTROL FOOTING group, then each time the other group is executed, the value of its sum counter is added to the value of the sum counter of the current group.
Listing 18-3 contains good examples of both subtotaling and rolling forward. Example 18-6 provides a reminder of the relevant code. Each time a DETAIL line is GENERATED, the ValueOf Sale is added to the TotalAgentSales sum counter. When a control break occurs on SalesAgentNum, the accumulated sum is printed and is added to the TotalStateSales sum counter. When a control break occurs on StateNum, the sum accumulated in the TotalStateSales sum counter is added to the final total sum counter.
Example 18-6. Subtotaling and Rolling Forward from Listing 18-3
01 SalesAgentGrp
TYPE IS CONTROL FOOTING SalesAgentNum NEXT GROUP PLUS 2.
: : : : : : : : : : : : : : :
03TotalAgentSalesCOLUMN 45 PIC $$$$$,$$$.99 SUMValueOfSale.
01 StateGrp TYPE IS CONTROL FOOTING StateNum NEXT GROUP PLUS 2.
02 LINE IS PLUS 2.
: : : : : : : : : : : : : : :
03TotalStateSalesCOLUMN 45 PIC $$$$$,$$$.99 SUMTotalAgentSales.
01 TotalSalesGrp TYPE IS CONTROL FOOTING FINAL.
: : : : : : : : : : : : : : :
03 COLUMN 48 PIC $$,$$$,$$$.99 SUMTotalStateSales.
Crossfooting
In crossfooting, the sum counters in the same CONTROL FOOTING group can be added together to create another sum counter. In Example 18-7, each time a GENERATE statement is executed, the value of NetWeightOfGoods (in the file record) is added to the NWG sum counter, and the value of WeightOfPackingMaterials (in the file record) is added to WPM (subtotaling). When a control break occurs on OrderNumber, the values of the NWG and WPM sum counters are added together to give the combined total identified as GrossWeight and printed in column 40 (crossfooting).
Example 18-7. Crossfooting to Create the GrossWeight Sum Counter
01 ShippingGrp
TYPE IS CONTROL FOOTING OrderNumber NEXT GROUP PLUS 3.
: other entries :
: other entries :
03 NWG COLUMN 20 PIC Z,ZZ9 SUM NetWeightOfGoods.
03 WPM COLUMN 30 PIC ZZ9 SUM WeightOfPackingMaterials.
03 GrossWeight COLUMN 40 PIC ZZ,ZZ9 SUM GNW, PMW.
The RESET ON Clause
Sum counters are normally reset to zero after a control break on the control-break item associated with the report group. For instance, in Example 18-6, if you wanted SalesAgentGrp to show a rolling total of the sales in the state, you could change SalesAgentGrp as shown in Example 18-8. In this example, TotalAgentSales prints the sales of a particular agent and is reset to zero when the footer group is printed, whereas StateSalesToDate prints a rolling total of sales for the state and is reset to zero only when there is a control break on StateNum.
Example 18-8. Using the RESET ON Clause
01 SalesAgentGrp
TYPE IS CONTROL FOOTING SalesAgentNum NEXT GROUP PLUS 2.
: : : : : : : : : : : : : : :
03 TotalAgentSales COLUMN 45 PIC $$$$$,$$$.99 SUM ValueOfSale.
03 StateSalesToDate COLUMN 60 PIC $$$$$,$$$.99 SUM ValueOfSale
RESET ON StateNum.
Special Report Writer Registers
The Report Writer maintains two special registers for each report declared in the REPORT SECTION.: LINE-COUNTER and PAGE-COUNTER.
LINE-COUNTER
LINE-COUNTER is a reserved word that can be used to access a special register that the Report Writer maintains for each report in the REPORT SECTION. The Report Writer uses the LINE-COUNTER register to keep track of where the lines are being printed on the report. It uses this information and the information specified in the PAGE LIMIT clause in the RD entry to decide when a new page is required.
Although the LINE-COUNTER register can be used as a SOURCE item in the report, no statements in the PROCEDURE DIVISION can alter the value in the register.
References to the LINE-COUNTER register can be qualified by referring to the name of the report given in the RD entry.
PAGE-COUNTER
The reserved word PAGE-COUNTERis used to access a special register that the Report Writer maintains for each report in the REPORT SECTION. It keeps track of the number of pages printed in the report. The PAGE-COUNTER register can be used as a SOURCE item in the report, but the value of the PAGE-COUNTER may also be changed by statements in the PROCEDURE DIVISION .
PROCEDURE DIVISION Report Writer Verbs
The Report Writer introduces four new verbs for processing reports:
The first three are normal PROCEDURE DIVISION verbs, but the last one can only be used in the declaratives. I will postpone discussion of that verb until I deal with declaratives.
An INITIATE statement starts the processing of the ReportName report or reports. The metalanguage for the INITIATE verb is given in Figure 18-6.
Figure 18-6. Metalanguage for the INITIATE verb
Before INITIATE is executed, the file associated with the ReportName must have been opened for OUTPUT or EXTEND. This is illustrated in Listing 18-3 by these statements:
SELECTPrintFileASSIGN TO "Listing18-3.Rpt".
: : : : : : : : :
FD PrintFile
REPORT ISSolaceSalesReport.
: : : : : : : : :
RD SolaceSalesReport
: : : : : : : : :
OPEN OUTPUTPrintFile
: : : : : : : : :
INITIATESolaceSalesReport
The GENERATE statement drives the production of the report. The metalanguage for GENERATE is given in Figure 18-7.
Figure 18-7. Metalanguage for the GENERATE verb
The target of a GENERATE statement is either a DETAIL report group or a ReportName. When the target is a ReportName, the report description must contain the following:
When all the GENERATE statements for a particular report target the ReportName, the report performs summary processing only, and the report produced is called a summary report. For instance, to make a summary report using Listing 18-3, all you have to do is change
GENERATE DetailLine
to
GENERATE SolaceSalesReport.
If you specify GENERATE SolaceSalesReport, then the DETAIL group is never printed, but the other groups are printed.
You use a TERMINATE statement to instruct the Report Writer to finish the processing of the specified report. The metalanguage for TERMINATE is given in Figure 18-8.
Figure 18-8. Metalanguage for the TERMINATE verb
When TERMINATE is executed, the Report Writer prints the PAGE and REPORT FOOTING groups, and all the CONTROL FOOTING groups are printed as if there had been a control break on the most senior control group.
After the report has been terminated, the file associated with the report must be closed. For instance, in Listing 18-3, the TERMINATE SolaceSalesReport statement is followed by the CLOSE PrintFile statement.
Declaratives
The main structural elements of a COBOL program are divisions, sections, and paragraphs. This section introduces a new structural element: declaratives. When declaratives are used, they are the first element in the PROCEDURE DIVISION and start with the word DECLARATIVES and end with END DECLARATIVES. Declaratives specify USE procedures that are executed when certain conditions occur. You write the USE procedures in the declaratives in consecutive sections.
When declaratives are used, the remainder of the PROCEDURE DIVISION must consist of at least one section. Example 18-9 is a template the shows the structure of declaratives.
Example 18-9. Structure of Declaratives
PROCEDURE DIVISION.
DECLARATIVES
SectionName SECTION.
USE statement
ParagraphName.
COBOL Statements
END DECLARATIVES.
Main SECTION.
Declaratives are used for two main purposes:
Using Declaratives with the Report Writer
Declaratives are used to extend the functionality of the Report Writer by performing tasks or calculations that the Report Writer cannot do automatically or by selectively stopping a report group from being printed (using the SUPPRESS PRINTING command). When you use declaratives with the Report Writer, the USE BEFORE REPORTING phrase lets you specify that a particular section of code is to be executed before the identified report group is printed. The metalanguage for the USE statement used with the Report Writer is given in Figure 18-9.
Figure 18-9. Metalanguage for the Report Writer version of USE
Note the following:
Listing 18-3 has a good example of how declaratives may be used to extend the functionality of the Report Writer. They are used to calculate the sales agent SalesCommission and FullSalary before SalesAgentGrp is printed. For convenience, the code is repeated in Example 18-10.
Example 18-10. Declaratives from Listing 18-3
PROCEDURE DIVISION.
DECLARATIVES.
Calc SECTION.
USE BEFORE REPORTING SalesAgentGrp.
Calculate-Salary.
MULTIPLY TotalAgentSales BY Percentage
GIVING SalesCommission ROUNDED
ADD SalesCommission, BaseSalary(StateNum)
GIVING FullSalary.
END DECLARATIVES.
Main SECTION.
Begin.
OPEN INPUT SalesFile
OPEN OUTPUT PrintFile
The SUPPRESS PRINTING Statement
The SUPPRESS PRINTING statement is used in a DECLARATIVES section to stop a particular report group from being printed. The report group suppressed is the one mentioned in the USE statement associated with the section containing the SUPPRESS PRINTING statement. The SUPPRESS PRINTING statement must be executed each time you want to stop the report group from being printed.
In Example 18-11, the CONTROL FOOTING data for StateGrp is printed only if the state sales total is above a certain threshold.
Example 18-11. Suppressing the Printing of a Report Group
PROCEDURE DIVISION.
DECLARATIVES.
CheckStateSales SECTION.
USE BEFORE REPORTING StateGrp.
PrintImportantStatesOnly.
IF TotalStateSales < 100000
SUPPRESS PRINTING
END-IF.
END DECLARATIVES.
Control-Break Registers
The Report Writer maintains a special control-break register for each control-break item mentioned in the CONTROLS ARE phrase in the RD entry. When a control-break item is referred to in a control footer or in the declaratives, the Report Writer supplies the value held in the control-break register and not the value in the item itself. If a control break has just occurred, the value in the control-break register is the previous value of the control-break item.
This point is demonstrated in the report produced by Listing 18-3 by printing the actual state number (the one in the record buffer) and the supplied state number (the one in the control-break register) each time StateGrp group is printed.
Using Declaratives with Files
You can also use declaratives to handle file operation errors. The metalanguage for the version of USE used with files is given in Figure 18-10.
Figure 18-10. Metalanguage for the files version of USE
When you use this version of the declaratives, you can create code that deals with any I-O error on a particular file or more generalized code that deals with INPUT, OUTPUT, I-O, or EXTEND errors on any file. When declaratives exist for a file, the INVALID KEY clause and the AT END clause are optional.
The program fragment in Example 18-12 shows how you can use declaratives to handle errors on a particular file.
Example 18-12. Declarative Procedures to Handle Unexpected File Errors
PROCEDURE DIVISION.
DECLARATIVES.
SupFile SECTION.
USE AFTER ERROR PROCEDURE ON SupplierFile.
DisplaySupplierFileStatus.
DISPLAY "Unexpected error on Supplier file. Status = " SupplierStatus
DISPLAY "The file name used was :- " SupplierFileName
STOP RUN.
VidFile SECTION.
USE AFTER ERROR PROCEDURE ON VideoFile.
DisplayVideoFileStatus.
DISPLAY "Unexpected error on Video file. Status = " VideoStatus
DISPLAY "The file name used was :- " VidFileName
STOP RUN.
END DECLARATIVES.
Main SECTION.
Begin.
OPEN INPUT SupplierFile
OPEN INPUT VideoFile
etc
Summary
This chapter introduced you to the COBOL Report Writer. In a series of increasingly complex programs, you learned how to use the Report Writer to create control-break-based reports. You were introduced to a number of new verbs, clauses, sections, and concepts. You saw how to use the RD entry in the REPORT SECTION to specify control-break items and define the basic layout of the report page. You were introduced to the idea of a report group and shown how to create report groups linked to control-break items. You learned how to use the SUM clause for totaling and rolling forward. The final program demonstrated how to extend the capabilities of the Report Writer by using declaratives. You then covered the verbs, clauses, and concepts of the Report Writer. And in the final section, you saw how to use declaratives for error handling in files.
The final chapter introduces OO-COBOL. This book adheres to the ANS 85 COBOL standard, so the ISO 2002 OO-COBOL is somewhat outside its remit. Nevertheless, some of the drawbacks of contained subprograms are remedied by OO-COBOL, and it is from this perspective that I examine the topic. Do not expect a course in object-oriented programming.
PROGRAMMING EXERCISE
And now for a programming exercise that tests your understanding of the last two chapters. For this, you need a really sharp 2B pencil.
Introduction
Two months before the beginning of each semester, Campus Bookshop produces a Purchase Requirements Report. This report details the books that have to be purchased for the coming semester. In the past, this was done manually; but now management has decided to computerize the operation. Accordingly, lecturers’ requirements have been captured and the results used to update a purchase requirements file. This is a permanent file that contains details of the lecturers’ book requirements for both semesters.
You are required to write a program to produce a Purchase Requirements Report from the publisher, book, and purchase requirements files. The report should be sequenced on ascending publisher name and should only detail the purchase requirements for the semester under scrutiny.
The semester number (1 or 2) should be accepted from the user at the start of the program using a simple ACCEPT and DISPLAY.
File Descriptions
Purchase Requirements File (Indexed)
There is a record for each book title required by a lecturer. Note that a book may be required by more than one lecturer.
The report must be printed according to the print specification given in Figure 18-11.
Figure 18-11. Print specification for the Purchase Requirements Report
The publisher name must be suppressed after its first occurrence. The headings should be printed at the top of each page, and *** END OF REPORT *** should be printed on line 56 on the last page of the report.
Ordinarily, a new page is required after line 50.
The Qty field, which is a synonym for Copies-Required, should be zero suppressed up to but not including the last digit.
The page number field should also be zero suppressed.
PROGRAMMING EXERCISE: SOLUTION
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing18-4.
AUTHOR. MICHAEL COUGHLAN.
*The Campus Bookshop Purchase Requirements Report (DP291-91-EXAM)
*Originally written for VAX COBOL 1991
*Converted to Microfocus COBOL 2002
*Modified for COBOL book 2014
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT PurchaseReqFile ASSIGN TO "Listing18-4-PRF.DAT"
ORGANIZATION IS INDEXED
FILE STATUS IS FileStatus-PRF
ACCESS MODE IS DYNAMIC
RECORD KEY IS PRNumber-PRF
ALTERNATE RECORD KEY IS LecturerName-PRF
WITH DUPLICATES
ALTERNATE RECORD KEY IS BookNum-PRF
WITH DUPLICATES.
SELECT BookFile ASSIGN TO "Listing18-4-BF.DAT"
ORGANIZATION IS INDEXED
FILE STATUS IS FileStatus-BF
ACCESS MODE IS DYNAMIC
RECORD KEY IS BookNum-BF
ALTERNATE RECORD KEY IS PublisherNum-BF
WITH DUPLICATES.
SELECT PublisherFile ASSIGN TO "Listing18-4-PF.DAT"
ORGANIZATION IS INDEXED
FILE STATUS IS FileStatus-PF
ACCESS MODE IS DYNAMIC
RECORD KEY IS PublisherNum-PF
ALTERNATE RECORD KEY IS PublisherName-PF.
SELECT ReportFile ASSIGN TO "Listing18-4.RPT".
DATA DIVISION.
FILE SECTION.
FD PurchaseReqFile.
01 PurchaseRec-PRF.
88 EndOfPRequirements VALUE HIGH-VALUES.
88 NotEndOfPRequirements VALUE LOW-VALUES.
02 PRNumber-PRF PIC 9(4).
02 LecturerName-PRF PIC X(20).
02 BookNum-PRF PIC 9(4).
02 ModuleCode-PRF PIC X(5).
02 CopiesRequired-PRF PIC 9(3).
02 Semester-PRF PIC 9.
FD BookFile.
01 BookRec-BF.
88 EndOfBooks VALUE HIGH-VALUES.
88 NotEndOfBooks VALUE LOW-VALUES.
02 BookNum-BF PIC 9(4).
02 PublisherNum-BF PIC 9(4).
02 BookTitle-BF PIC X(30).
FD PublisherFile.
01 PublisherRec-PF.
88 EndOfPublishers VALUE HIGH-VALUES.
02 PublisherNum-PF PIC 9(4).
02 PublisherName-PF PIC X(20).
02 PublisherAddress-PF PIC X(40).
FD ReportFile
REPORT IS PurchaseRequirementsReport.
WORKING-STORAGE SECTION.
01 File-Stati.
02 FileStatus-PRF PIC X(2).
88 PurchaseRec-PRF-Not-Found VALUE "23".
02 FileStatus-BF PIC X(2).
88 BookRec-Not-Found VALUE "23".
02 FileStatus-PF PIC X(2).
01 Current-Semester PIC 9.
REPORT SECTION.
RD PurchaseRequirementsReport
CONTROLS ARE FINAL
PublisherName-PF
PAGE LIMIT IS 66
HEADING 2
FIRST DETAIL 8
LAST DETAIL 50
FOOTING 55.
01 TYPE IS REPORT FOOTING.
02 LINE 56.
03 COLUMN 29 PIC X(23)
VALUE "*** END OF REPORT ***".
01 TYPE IS PAGE HEADING.
02 LINE 2.
03 COLUMN 27 PIC X(30)
VALUE "PURCHASE REQUIREMENTS REPORT".
03 COLUMN 77 PIC X(6)
VALUE "PAGE :".
03 COLUMN 84 PIC Z9 SOURCE PAGE-COUNTER.
02 LINE 3.
03 COLUMN 26 PIC X(32) VALUE ALL "-".
02 LINE 6.
03 COLUMN 2 PIC X(24) VALUE "PUBLISHER NAME".
03 COLUMN 33 PIC X(11) VALUE "BOOK TITLE".
03 COLUMN 57 PIC X(3) VALUE "QTY".
03 COLUMN 65 PIC X(14) VALUE "LECTURER NAME".
01 PReq-PrintLine TYPE IS DETAIL.
02 LINE IS PLUS 2.
03 COLUMN 1 PIC X(20) SOURCE PublisherName-PF
GROUP INDICATE.
03 COLUMN 24 PIC X(30) SOURCE BookTitle-BF.
03 COLUMN 57 PIC ZZ9 SOURCE CopiesRequired-PRF.
03 COLUMN 63 PIC X(20) SOURCE LecturerName-PRF.
PROCEDURE DIVISION.
BEGIN.
DISPLAY "Enter the semester number (1 or 2) - " WITH NO ADVANCING
ACCEPT Current-Semester
OPEN INPUT PurchaseReqFile
OPEN INPUT BookFile
OPEN INPUT PublisherFile
OPEN OUTPUT ReportFile
INITIATE PurchaseRequirementsReport
MOVE SPACES TO PublisherName-PF
START PublisherFile
KEY IS GREATER THAN PublisherName-PF
INVALID KEY DISPLAY "START Pub file status" FileStatus-PF
END-START
READ PublisherFile NEXT RECORD
AT END SET EndOfPublishers TO TRUE
END-READ
PERFORM PrintRequirementsReport UNTIL EndOfPublishers
TERMINATE PurchaseRequirementsReport
CLOSE PurchaseReqFile, BookFile,
PublisherFile, ReportFile
STOP RUN.
PrintRequirementsReport.
SET NotEndOfBooks TO TRUE
MOVE PublisherNum-PF TO PublisherNum-BF
READ BookFile
KEY IS PublisherNum-BF
INVALID KEY
DISPLAY SPACES
DISPLAY "Book File Error. FileStatus = " FileStatus-BF
DISPLAY "Publisher Number - " PublisherNum-BF
DISPLAY "Publisher Rec = " PublisherRec-PF
MOVE ZEROS TO PublisherNum-BF
END-READ
PERFORM ProcessPublisher
UNTIL PublisherNum-PF NOT EQUAL TO PublisherNum-BF
OR EndOfBooks
READ PublisherFile NEXT RECORD
AT END SET EndOfPublishers TO TRUE
END-READ.
ProcessPublisher.
SET NotEndOfPRequirements TO TRUE
MOVE BookNum-BF TO BookNum-PRF
READ PurchaseReqFile
KEY IS BookNum-PRF
INVALID KEY
DISPLAY SPACES
DISPLAY "PurchReqFile Error. FileStatus = " FileStatus-PRF
DISPLAY "Book Num PRF = " BookNum-PRF
DISPLAY "Book Rec = " BookRec-BF
MOVE ZEROS TO BookNum-PRF
END-READ
PERFORM UNTIL BookNum-BF NOT EQUAL TO BookNum-PRF
OR EndOfPRequirements
IF Current-Semester = Semester-PRF THEN
Generate PReq-PrintLine
END-IF
READ PurchaseReqFile NEXT RECORD
AT END SET EndOfPRequirements TO TRUE
END-READ
END-PERFORM
READ BookFile NEXT RECORD
AT END SET EndOfBooks TO TRUE
END-READ.
18.117.192.247