GnuCOBOL’s Report Writer Module

I am finally to my goal made at the beginning of this (lousy) year! Use embedded SQL to extract data from a database and the COBOL report writer to produce a printed report. Thus, this is the last planned post for GnuCOBOL.

In 1979 when I started my career, I was a programmer for (what is now) Texas Statue University’s Administrative Data Processing department. Paper reports were big and even bigger at the university where few humans in the Admin dept had access to a terminal.

A year later I went on to a much better paid position (the university could get by with paying less than minimum wage) where I used COBOL on a Hewlett-Packard HP3000 which was my machine of choice for the rest of my professional programming career. UNFORTUNATELY, HP decided not to implement the Report Writer module (the Report Writer was an optional module in the COBOL standard).

I can remember banging my head on the wall because it was extremely boring to have to manage the details of writing a report by hand. As time went by I eventually completely forgot how the Report Writer even works, but I never forgot I would prefer to have it!

To write the test program for this post, I had to relearn the report writer. It really isn’t too difficult to do so. But you do have to learn quite a few things simultaneously to make it work.

Note, I had originally intended to also use SORT INPUT/OUTPUT PROCEDURES to sort the data as done in the prior post. My initial version of the program did that, but there was a lot more code than I wanted for an example. Given one most likely wouldn’t use COBOL SORT when extracting data from a database, I decided to forgo the COBOL SORT.

Resources

The GnuCOBOL manual (3.1) has an entire section (section 9) on how to use the Report Writer. I also found this tutorial quite useful.

COBOL Report Writer Feature

It is written for IBM MVT COBOL, but there are few differences between that and GnuCOBOL.

The GnuCOBOL FAQ also has a section on the report writer, with an example derived from the above tutorial.

Designing The Report

As with the prior example, I want to design a DVD rental history report but now that I’m using the report writer, it will have headings, counts, and footings. A real report.

As I was working on this projects, I thought back to the president of the company I worked at long ago. He designed ALL reports and we programmers implemented them. The reports were the face of our company and he wanted them to look good. Indeed they did, his reports were probably the best I’ve seen. Especially these days when many reports are just an after thought.

When he gave us a report to implement it was on an official IBM Report Layout form like this (found at http://ibm-1401.info/IBM1401_ArchivePics.html)

Totally off topic, but notice the Carriage Control Tape column on the far left. When using old printers like the IBM 1403, you could advance to a particular line by if there was a punch in that tape. Channel 1 of the tape was always top of the form and typically we used used a tape with only that channel punched. But if you need to print a report that was largely empty space, like may be a check or a utility bill, you could very quickly slew to the line you needed by advancing to the appropriate channel. For example:

WRITE PRINT-REC AFTER ADVANCING TO-CHECK-AMT-LINE.

That old 1403 printer could print amazingly fast for something so large. And standing next to it was about like standing next to a gattling gun (or so it seems to me now).

Popping the stack back to my original train of thought: My input data is this data base:

I’ll use this query to extract the data:

select 
    customer.customer_id,
    customer.last_name,
    customer.first_name,
    film.title,
    to_char(rental.return_date,'yyyymmdd') as 
        sorteddate
from customer
inner join rental    on 
    customer.customer_id = rental.customer_id
left  join inventory on 
    rental.inventory_id  = inventory.inventory_id
left  join film      on 
    inventory.film_id    = film.film_id
order by customer.last_name, customer.first_name, 
    sorteddate

and will produce a report that looks like this:

11/12/2020                                               PAGE:  1
---------------------CUSTOMER HISTORY REPORT---------------------

------------NAME------------ CUST                      ---DATE---
-----LAST------ ---FIRST---- -ID- -----DVD TITLE------ -RETURNED-

I will want to report the total DVDs each customer has rented, the total number of DVDs rented, and the total number of customers reported.

A Simpler Report Writer Program First

It took me some time to get my head around the operation of the report writer.It’s not hard, just different. nearly everything is specified in the DATA DIVISION not the PROCEDURE DIVISION.

I started by writing a program that didn’t do report control breaks. Omitting the control footings makes the reporting easier to understand.

The program source can be found at http://www.xyfyx.com/files/reportWriter01.cob

Here is notable parts of the code with comments:

Below is the output file that will contain the report. LINE SEQUENTIAL indicates when each line is written it should be terminated with the appropriate line terminator for the operating system being used.

 ENVIRONMENT DIVISION.
 INPUT-OUTPUT SECTION.
 FILE-CONTROL.
 
     SELECT RF-REPORT-FILE,
         ASSIGN TO               "./reportWriter01.lst",
         ORGANIZATION IS         LINE SEQUENTIAL.
...         
 FD  RF-REPORT-FILE,
     REPORT IS                   RF-REPORT.

These fields are used to format dates:

 WORKING-STORAGE SECTION.

...

 01  DB-REC.
     03  DB-CUSTID               PIC 9(9).
     03  DB-LASTNAME             PIC X(45).
     03  DB-FIRSTNAME            PIC X(45).
     03  DB-FILMTITLE            PIC X(45).
     03  DB-RETURNDATE           PIC 99999999.

...

 01  TF-TEMP-FIELDS.
     03  TF-DATE-IN.
         05  TF-YY               PIC 9999.
         05  TF-MM               PIC 99.
         05  TF-DD               PIC 99.
     03  TF-DATE-OUT             PIC X(10).    
     03  TF-RUNDATE-IN.
         05  TF-RUNDATE-YY       PIC 9999.
         05  TF-RUNDATE-MM       PIC 99.
         05  TF-RUNDATE-DD       PIC 99.
     03  TF-RUNDATE-OUT          PIC X(10).    
         
... 

At the end of the DATA DIVISION is the REPORT SECTION which will describe (usually) everything needed to produce the report.

  • Page Limit: Number of lines per page.
  • Heading: line upon which the first header line is printed.
  • First Detail: line upon which the first detail line is printed.
  • Last detail: line upon which the last detail line of the page can be printed.
REPORT SECTION.

RD  RF-REPORT,
    PAGE LIMIT                  66 LINES,
    HEADING                     1,
    FIRST DETAIL                7,
    LAST DETAIL                 60.

This next section defines the header lines to be printed. The first line is on the absolute position of LINE 1, then each line after is placed on the next physical line (LINE PLUS 1) or 2 lines down (LINE PLUS 2).

Within each line are column definitions. For this report I’m specifying exact column placement. SOURCE indicated this column will contain the specified field using the specified PIC. So the report’s run date starts in column 1, comes from TF-RUNDATE-OUT and will take 20 characters.

The constant “PAGE” is placed at column 58. Note that you do not have to use PIC for values. The next example will show a more concise page definition.

01  PAGE-HEAD-GROUP TYPE PAGE HEADING.
    03  LINE 1.
        05  COLUMN 1            PIC X(20),
                SOURCE TF-RUNDATE-OUT.
        05  COLUMN 58           PIC X(6),
                VALUE "PAGE: ".
        05  COLUMN 64           PIC Z9,
                SOURCE PAGE-COUNTER.
    03  LINE PLUS 1.
        05  COLUMN 1            PIC X(21),
                VALUE ALL "-".
        05  COLUMN 22            PIC X(23),
                VALUE "CUSTOMER HISTORY REPORT".
        05  COLUMN 45           PIC X(21),
                VALUE ALL "-".
    03  LINE PLUS 2.
        05  COLUMN 1            PIC X(28),
                VALUE "------------NAME------------".
        05  COLUMN 30           PIC XXXX,
                VALUE "CUST".
        05  COLUMN 56           PIC X(10),
                VALUE "---DATE---".
    03  LINE PLUS 1.
        05  COLUMN 1            PIC X(15),
                VALUE "-----LAST------".
        05  COLUMN 17           PIC X(12),
                VALUE "---FIRST----".
        05  COLUMN 30           PIC XXXX,
                VALUE "-ID-".
        05  COLUMN 35           PIC X(20),
                VALUE "-----FILM TITLE-----".
        05  COLUMN 56           PIC X(10),
                VALUE "-RETURNED-".

The detail line is laid out in the same manner. Each field is SOURCEd from the database record (except the date).

01  DETAIL-LINE TYPE DETAIL.
    03  LINE PLUS 1.
        05  COLUMN 1            PIC X(15),
                SOURCE DB-LASTNAME.
        05  COLUMN 17           PIC X(12),
                SOURCE DB-FIRSTNAME.
        05  COLUMN 30           PIC ZZZ9,
                SOURCE DB-CUSTID.
        05  COLUMN 35           PIC X(20),
                SOURCE DB-FILMTITLE.
        05  COLUMN 56           PIC X(10),
                SOURCE TF-DATE-OUT.
...

In the procedure division, the RUN DATE is derived from the system date:

    ACCEPT TF-RUNDATE-IN            FROM DATE YYYYMMDD.
    STRING TF-RUNDATE-MM, "/", TF-RUNDATE-DD, "/", 
        TF-RUNDATE-YY               INTO TF-RUNDATE-OUT.
...

After the cursor is setup, we are ready to begin reading records and printing them. DON’T forget to open the report file (I did at first. No error is generated, but I couldn’t find any output).

The INITIATE verb initiates the report.

    OPEN OUTPUT RF-REPORT-FILE.
    INITIATE RF-REPORT.
...

This is the “heart” of printing. Each line is read from the database, and we simply GENERATE-DETAIL line to print the report – it handles all of the details of printing for us.

    PERFORM UNTIL SQLCODE NOT = ZERO,
        ...    
        GENERATE DETAIL-LINE;
        
        EXEC SQL 
            FETCH C1 INTO 
                :DB-CUSTID,
                :DB-LASTNAME,
                :DB-FIRSTNAME,
                :DB-FILMTITLE,
                :DB-RETURNDATE
        END-EXEC;
    END-PERFORM.
...

We’ve read all of the data, so terminate the report, and close it.

    TERMINATE RF-REPORT.    
    CLOSE RF-REPORT-FILE.
...

As you can see ALL of the work of generating the report is setting up the REPORT SECTION. Even without the report writer you still have to define how the output will appear, so there isn’t much extra necessary to use the report writer.

Compile and run:

$export COBCPY=~/Open-COBOL-ESQL-1.2/copy
$export COB_LDFLAGS=-Wl,--no-as-needed
$ocesql reportWriter01.cob reportWriter01.tmp
precompile start: reportWriter01.cob
=======================================================
              LIST OF CALLED DB Library API            
=======================================================
;
;
;
;
;
;
Generate:OCESQLConnect
Generate:OCESQLCursorDeclare
Generate:OCESQLCursorOpen
Generate:OCESQLCursorFetchOne
Generate:OCESQLCursorFetchOne
Generate:OCESQLCursorClose
Generate:OCESQLDisconnect
Generate:ROLLBACK
=======================================================
$cobc  -locesql -x reportWriter01.tmp

Excerpts from the output file:

less reportWriter01.lst 

11/11/2020                                               PAGE:  1
---------------------CUSTOMER HISTORY REPORT---------------------

------------NAME------------ CUST                      ---DATE---
-----LAST------ ---FIRST---- -ID- -----FILM TITLE----- -RETURNED-

Abney           Rafael        505 Sagebrush Clueless   05/29/2005
Abney           Rafael        505 Pocus Pulp           06/05/2005
Abney           Rafael        505 Legally Secretary    06/19/2005
Abney           Rafael        505 Nightmare Chill      06/20/2005
Abney           Rafael        505 Trading Pinocchio    06/28/2005
Abney           Rafael        505 Coneheads Smoochy    06/28/2005
Abney           Rafael        505 Wanda Chamber        07/12/2005
Abney           Rafael        505 Madness Attacks      07/14/2005
Abney           Rafael        505 Conquerer Nuts       07/14/2005

...

Adams           Kathleen       36 Go Purple            06/20/2005
Adams           Kathleen       36 Betrayed Rear        07/10/2005
Adams           Kathleen       36 Room Roman           07/11/2005


11/11/2020                                               PAGE:  2
---------------------CUSTOMER HISTORY REPORT---------------------

------------NAME------------ CUST                      ---DATE---
-----LAST------ ---FIRST---- -ID- -----FILM TITLE----- -RETURNED-

Adams           Kathleen       36 Boogie Amelie        07/12/2005
Adams           Kathleen       36 Swarm Gold           07/12/2005
Adams           Kathleen       36 Amadeus Holy         07/16/2005

...

11/11/2020                                               PAGE: 98
---------------------CUSTOMER HISTORY REPORT---------------------

------------NAME------------ CUST                      ---DATE---
-----LAST------ ---FIRST---- -ID- -----FILM TITLE----- -RETURNED-

Young           Cynthia        28 Ice Crossing         08/23/2005
Young           Cynthia        28 Saddle Antitrust     08/24/2005
Young           Cynthia        28 Lebowski Soldiers    08/27/2005
Young           Cynthia        28 Loverboy Attacks     08/27/2005
Young           Cynthia        28 Attacks Hate         08/28/2005
Young           Cynthia        28 Suspects Quills      00/00/0000

The Final Version of the Program

The above report handles the header and detail lines great. Now I want to add in control breaks to report the number of DVDs each customer has rented, and at the end the total number of DVDs rented and the total number of customers reported.

Unfortunately there was no dollar amounts in this data upon which to report. The report writer can handle totaling detail line amounts with almost no more work than the above report by just using the SUM clause.

Instead, I want to count records which will add just a slight bit more complexity.

The source to this program can be found at http://www.xyfyx.com/files/reportWriter02.cob.

Here are notable parts of the code with comments:

 IDENTIFICATION DIVISION.

...

 WORKING-STORAGE SECTION.

I’m going to need CS-1, a constant of ONE used to add each DVD detail printed. I’m also going to need a counter to track the total number of customers reported.

 01  CS-CONSTANTS.
     03  CS-1                    PIC S9(4), COMP     VALUE 1.
 01  CT-COUNTERS.
     03  CT-CUSTS                PIC S9(9), COMP     VALUE ZERO.

...

I made a couple of changes for the database record read. I added DB-CUSTNAME. I need to know if either DB-LASTNAME or DB-FIRSTNAME changes, so I grouped them into DB-CUSTNAME.

I also altered how I handle DB-RETURNDATE. I want to STRING month, day, year together but OCESQL requires that the field containing the date from the database be an elementary item. To more cleanly handle this, I REDEFINE DB-RETURNDATE which allows access to the individual fields.

 01  DB-REC.
     03  DB-CUSTID               PIC 9(9).
     03  DB-CUSTNAME.
         05  DB-LASTNAME         PIC X(45).
         05  DB-FIRSTNAME        PIC X(45).
     03  DB-DVDTITLE             PIC X(45).
     03  DB-RETURNDATE           PIC 99999999.
     03  FILLER REDEFINES        DB-RETURNDATE.
         05  DB-YYYY             PIC 9999.
         05  DB-MM               PIC 99.
         05  DB-DD               PIC 99.
     
...

* ---------------------------------------------------------------
 REPORT SECTION.

In the RD, I now have the controls FINAL and DB-CUSTNAME. Every time DB-CUSTNAME changes a control break occurs. Also at the end of the report (FINAL) a control break occurs.

  RD  RF-REPORT,                  
     CONTROLS ARE                FINAL, DB-CUSTNAME,     
     PAGE LIMIT                  60 LINES,
     HEADING                     1,
     FIRST DETAIL                7,
     LAST DETAIL                 60.
...

I made a slight change to the header. Line 1 now contains a form feed character which will allow it to print on pretty much any modern printer.

    
 01  PAGE-HEAD-GROUP TYPE PAGE HEADING.
     03  LINE 1.                 *> *** FORMFEED
         05  COLUMN 1            VALUE X'0C'.
     03  LINE PLUS 1.
         05  COLUMN 1            PIC X(20),
             SOURCE TF-RUNDATE-OUT.
         05  COLUMN 58           VALUE "PAGE: ".
         05  COLUMN 64           PIC Z9,
             SOURCE PAGE-COUNTER.

In this report, I drop absolute column positions (except COLUMN 1) and use relative (PLUS n). In this next section, each field is adjacent to the next so I use PLUS 1. Typically I would want a space between columns and in the detail line you will see everything set at PLUS 2.

Also note that the PIC clause is now omitted as well. If omitted, the compiler derives the length from the VALUE clause.

     03  LINE PLUS 1.
         05  COLUMN 1            PIC X(21),
             VALUE ALL "-".
         05  COLUMN PLUS 1       VALUE "CUSTOMER HISTORY REPORT".
         05  COLUMN PLUS 1       PIC X(21),
             VALUE ALL "-".
     03  LINE PLUS 2.
         05  COLUMN 1            VALUE "------------".
         05  COLUMN PLUS 1       VALUE "NAME------------".
         05  COLUMN PLUS 2       VALUE "CUST".
         05  COLUMN 56           VALUE "---DATE---".
     03  LINE PLUS 1.
         05  COLUMN 1            VALUE "-----LAST------".
         05  COLUMN PLUS 2       VALUE "---FIRST----".
         05  COLUMN PLUS 2       VALUE "-ID-".
         05  COLUMN PLUS 2       VALUE "-----DVD TITLE------".
         05  COLUMN PLUS 2       VALUE "-RETURNED-".

The DETAIL-LINE is very nearly like the last report. Each column contains the appropriate PIC clause to format the data, a SOURCE clause indicating where to obtain the data, and a relative column position.

Note the use of GROUP INDICATE. This clause causes the associated field to be omitted after the first time it is printed on each page. This makes the report much easier to read and saves some ink as well.

 01  DETAIL-LINE TYPE DETAIL.
     03  LINE PLUS 1.
         05  COLUMN 1            PIC X(15),
             SOURCE DB-LASTNAME,
             GROUP INDICATE.                 *> PRINTS ONLY ONCE
         05  COLUMN PLUS 2       PIC X(12),
             SOURCE DB-FIRSTNAME,
             GROUP INDICATE.
         05  COLUMN PLUS 2       PIC ZZZ9,
             SOURCE DB-CUSTID,
             GROUP INDICATE.
         05  COLUMN PLUS 2       PIC X(20),
             SOURCE DB-DVDTITLE.
         05  COLUMN PLUS 2       PIC X(10),
             SOURCE TF-DATE-OUT.

This is the footing group that will print at the end of each customer. In consists simply of a label and the number of DVDs rented.

The DVD count is obtained by using SUM CS-1. This will add 1 to an internal counter for each detail line printed for the customer. Had the database contained an amount field, say DB-AMOUNT, you could use SUM DB-AMOUNT and get the total amount for all records.

 01  CUST-TOTAL TYPE CONTROL FOOTING DB-CUSTNAME,
     NEXT GROUP IS PLUS 2.
     03  LINE PLUS 1.
         05  COLUMN 35           VALUE "---CUSTOMER RENTALS:".
         05  COLUMN 61           PIC Z,ZZ9,
             SUM CS-1.           *> *** ADDING 1 PER RECORD

Here is the report totals print group (FINAL FOOTING).

The total DVDs rented is obtains in the same manner as above, by SUMming CS-1.

The customer count has to manually be calculated.

 01  FINAL-GROUP TYPE CONTROL FOOTING FINAL.
     03  LINE PLUS 2.
         05  COLUMN 35           VALUE "------TOTAL RENTALS:".
         05  COLUMN 59           PIC ZZZ,ZZ9,
             SUM CS-1.
     03  LINE PLUS 2.
         05  COLUMN 35           VALUE "----TOTAL CUSTOMERS:".
         05  COLUMN 59           PIC ZZZ,ZZ9,
             SOURCE CT-CUSTS.

* ---------------------------------------------------------------
 PROCEDURE DIVISION.

Here is how the customer count is calculated, in the DECLARATIVES.

This bit of code is executed before each CUST-TOTAL report footing (e.g. the end of each customer).

It simply adds 1 to CT-CUSTS to maintain a running count of customers encountered during the report print.

 
 DECLARATIVES.
 
 00 SECTION.
     USE BEFORE REPORTING CUST-TOTAL.
 
 00-CUST-TOTAL.
 
     ADD 1                       TO CT-CUSTS.
 
 END DECLARATIVES.    

...

The report is generated in the same manner (with a slight change in how I used STRING to generate the date).

     OPEN OUTPUT RF-REPORT-FILE.
     INITIATE RF-REPORT.

     PERFORM UNTIL SQLCODE NOT = ZERO,
         STRING DB-MM, "/", DB-DD, "/", DB-YYYY
             INTO                TF-DATE-OUT;
             
         GENERATE DETAIL-LINE;
         
         EXEC SQL 
             FETCH C1 INTO 
                 :DB-CUSTID,
                 :DB-LASTNAME,
                 :DB-FIRSTNAME,
                 :DB-DVDTITLE,
                 :DB-RETURNDATE
         END-EXEC;
     END-PERFORM.

     TERMINATE RF-REPORT.    
     CLOSE RF-REPORT-FILE.

...         

To compile and run the final report:

$export COBCPY=~/Open-COBOL-ESQL-1.2/copy
$export COB_LDFLAGS=-Wl,--no-as-needed
$ocesql reportWriter02.cob reportWriter02.tmp
precompile start: reportWriter02.cob
=======================================================
              LIST OF CALLED DB Library API            
=======================================================
;
;
;
;
;
;
Generate:OCESQLConnect
Generate:OCESQLCursorDeclare
Generate:OCESQLCursorOpen
Generate:OCESQLCursorFetchOne
Generate:OCESQLCursorFetchOne
Generate:OCESQLCursorClose
Generate:OCESQLDisconnect
Generate:ROLLBACK
=======================================================
$cobc  -locesql -x reportWriter02.tmp

Excerpts from the output file:

^L
11/12/2020                                               PAGE:  1
---------------------CUSTOMER HISTORY REPORT---------------------

------------NAME------------ CUST                      ---DATE---
-----LAST------ ---FIRST---- -ID- -----DVD TITLE------ -RETURNED-
Abney           Rafael        505 Sagebrush Clueless   05/29/2005
                                  Pocus Pulp           06/05/2005
                                  Legally Secretary    06/19/2005
                                  Nightmare Chill      06/20/2005
                                  Trading Pinocchio    06/28/2005
                                  Coneheads Smoochy    06/28/2005
                                  Wanda Chamber        07/12/2005
                                  Madness Attacks      07/14/2005
                                  Conquerer Nuts       07/14/2005
                                  Double Wrath         07/16/2005
                                  Goodfellas Salute    07/20/2005
                                  Hobbit Alien         08/05/2005
                                  Shock Cabin          08/06/2005
                                  Karate Moon          08/08/2005
                                  Juggler Hardly       08/10/2005
                                  Strictly Scarface    08/20/2005
                                  Blackout Private     08/23/2005
...

                                  Freddy Storm         08/28/2005
                                  Chocolat Harry       08/28/2005
                                  Clash Freddy         08/28/2005
                                  Conversation Downhil 00/00/0000
                                  ---CUSTOMER RENTALS:         21


Adam            Nathaniel     504 Kiss Glory           05/31/2005
                                  Gathering Calendar   06/04/2005
                                  Noon Papi            06/06/2005
                                  Guys Falcon          06/26/2005
                                  Shepherd Midsummer   06/27/2005
                                  Ending Crowds        07/12/2005
                                  Hanging Deep         07/13/2005
                                  Chasing Fight        07/15/2005
                                  Something Duck       07/15/2005
                                  Nemo Campus          07/18/2005
                                  Poseidon Forever     07/30/2005
                                  Divorce Shining      07/30/2005
                                  Jason Trap           08/01/2005
                                  Sleuth Orient        08/02/2005
                                  Tramp Others         08/03/2005
                                  Tights Dawn          08/04/2005
                                  Rocky War            08/07/2005
                                  Amadeus Holy         08/10/2005
                                  Lust Lock            08/21/2005
                                  Wardrobe Phantom     08/22/2005
                                  Menagerie Rushmore   08/24/2005
                                  Analyze Hoosiers     08/24/2005
                                  Dancing Fever        08/25/2005
                                  Boogie Amelie        08/25/2005
                                  Orient Closer        08/28/2005
                                  War Notting          08/28/2005
                                  Freddy Storm         08/30/2005
                                  Strangers Graffiti   08/31/2005
                                  ---CUSTOMER RENTALS:         28


^L
11/12/2020                                               PAGE:  2
---------------------CUSTOMER HISTORY REPORT---------------------

------------NAME------------ CUST                      ---DATE---
-----LAST------ ---FIRST---- -ID- -----DVD TITLE------ -RETURNED-
Adams           Kathleen       36 Orange Grapes        05/28/2005
                                  Alone Trip           06/01/2005
                                  Go Purple            06/20/2005
                                  Betrayed Rear        07/10/2005
                                  Room Roman           07/11/2005
                                  Boogie Amelie        07/12/2005
                                  Swarm Gold           07/12/2005
                                  Amadeus Holy         07/16/2005
                                  Sling Luke           07/30/2005
                                  Pianist Outfield     08/01/2005
                                  Seabiscuit Punk      08/01/2005
                                  Women Dorado         08/02/2005
                                  Wash Heavenly        08/02/2005
                                  Treatment Jekyll     08/03/2005

...

11/12/2020                                               PAGE: 40
---------------------CUSTOMER HISTORY REPORT---------------------

------------NAME------------ CUST                      ---DATE---
-----LAST------ ---FIRST---- -ID- -----DVD TITLE------ -RETURNED-
Young           Cynthia        28 Ship Wonderland      05/31/2005
                                  Star Operation       06/17/2005
                                  Dying Maker          06/18/2005
                                  Banger Pinocchio     06/23/2005
                                  Odds Boogie          06/25/2005
                                  Virginian Pluto      06/26/2005
                                  Wolves Desire        07/09/2005
                                  Kick Savannah        07/10/2005
                                  Deceiver Betrayed    07/12/2005
                                  Dalmations Sweden    07/16/2005
                                  Murder Antitrust     07/16/2005
                                  Papi Necklace        07/18/2005
                                  Spirit Flintstones   07/18/2005
                                  Trading Pinocchio    08/01/2005
                                  Wars Pluto           08/02/2005
                                  Lawless Vision       08/03/2005
                                  Clueless Bucket      08/03/2005
                                  Birch Antitrust      08/05/2005
                                  Easy Gladiator       08/05/2005
                                  License Weekend      08/05/2005
                                  Fiction Christmas    08/08/2005
                                  Candidate Perdition  08/09/2005
                                  Translation Summer   08/19/2005
                                  Minds Truman         08/21/2005
                                  Beverly Outlaw       08/21/2005
                                  Ice Crossing         08/23/2005
                                  Saddle Antitrust     08/24/2005
                                  Lebowski Soldiers    08/27/2005
                                  Loverboy Attacks     08/27/2005
                                  Attacks Hate         08/28/2005
                                  Suspects Quills      00/00/0000
                                  ---CUSTOMER RENTALS:         32

                                  ------TOTAL RENTALS:     16,044

                                  ----TOTAL CUSTOMERS:        599

Being the paranoid programmer I am, all totals were compared with the database and they match!

This concludes my foray into GnuCOBOL!

This entry was posted in c-gnuCOBOL and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.