Back to Contents


Reports

Summary:

See also: Programs, Variables, Result set.


Definition

A report can arrange and format the data according to your instructions and display the output on the screen, send it to a printer, or store it as a file for future use.

To implement a report, a program must include two distinct components:

The Report Driver retrieves the specified rows from a database, stores their values in program variables, and sends these - one input record at a time - to the Report Routine. After the last input record is received and formatted, the runtime system calculates any aggregate values based on all the data and sends the entire report to some output device.

By separating the two tasks of data retrieval and data formatting, the runtime system simplifies the production of recurrent reports and makes it easy to apply the same report format to different data sets.

The report engine supports the following features:

The report engine supports one-pass reports and two-pass reports. The one-pass requires sorted data to be produced by the report driver in order to handle before/after groups properly. The two-pass record handles sort internally and does not need sorted data from the report driver. During the first pass, the report engine sorts the data and stores the sorted values in a temporary file in the database. During the second pass, it calculates any aggregate values and produces output from data in the temporary files.


Report Engine Configuration

By default, GROUP aggregate functions such as SUM() return a NULL value if all items values are NULL. You can force the report engine to return a zero decimal value with the following FGLPROFILE setting:

Report.aggregateZero = {true|false}

When this entry is set to true, aggregate functions return zero when all values are NULL.

Default value is : false (Aggregate functions evaluate to NULL if all items are NULL)


The Report Driver

The Report Driver invokes the report, retrieves data, and sends the data (as input records) to be formatted by the REPORT program block (or routine). A Report Driver can be part of the MAIN program block, or it can be in one or more functions. The report driver typically consists of a loop (such as WHILE, FOR, or FOREACH) with the following statements to process the report:

Instruction Description
START REPORT This statement is required to instantiate the report driver. 
OUTPUT TO REPORT Provide data for one row to the report driver.
FINISH REPORT Normal termination of the report.
TERMINATE REPORT Cancels the processing of the report.

Usage:

A report driver is started by the START REPORT instruction. Once started, data can be given to the report driver through the OUTPUT TO REPORT statement. To instruct the report engine to terminate output processing, use the FINISH REPORT instruction.

It is possible to manage several report drivers at the same time. It is even possible to invoke a report driver inside a REPORT program block, which is different from the current driver.

The programmer must make sure that the runtime system will always execute these instructions in the following order:

  1. START REPORT
  2. OUTPUT TO REPORT
  3. FINISH REPORT

Example:

01 DATABASE stores7
02 MAIN
03   DEFINE rcust RECORD LIKE customer.*
04   DECLARE cu1 CURSOR FOR SELECT * FROM customer
05   START REPORT myrep
06   FOREACH cu1 INTO rcust.*
07      OUTPUT TO REPORT myrep(rcust.*)
08   END FOREACH
09   FINISH REPORT myrep
10 END MAIN

START REPORT

Syntax:

START REPORT report-name
  [  
   TO   
   {
      SCREEN
    | PRINTER
    | FILE filename
    | PIPE program { IN FORM MODE | IN LINE MODE } 
    | OUTPUT
      { 
         "SCREEN"
       | "PRINTER"
       | "FILE" DESTINATION filename
       | "PIPE { IN FORM MODE | IN LINE MODE }" DESTINATION program  
       | variable [ DESTINATION { program | filename } ]
      }
    }
  ]
  [ 
   WITH
   { 
     [ LEFT MARGIN = m-left [,] ] 
     [ RIGHT MARGIN  = m-right [,] ] 
     [ TOP MARGIN = m-top [,] ] 
     [ BOTTOM MARGIN = m-bottom [,] ] 
     [ PAGE LENGTH = m-length [,] ] 
     [ TOP OF PAGE = c-top  [,] ] 
   }
  ]
]

Notes:

  1. The START REPORT statement supersedes any clause in the output section of the report definition.
  2. report-name is a report that has been defined as a REPORT routine.
  3. filename is a string expression specifying the file that receives output.
  4. program is a string expression specifying a program, a shell script, or a command line to receive output.
  5. variable is a variable of type STRING that specifies one of: SCREEN, PRINTER, FILE, PIPE, PIPE IN LINE MODE, PIPE IN FORM MODE. If PRINTER is specified, the DBPRINT environment variable specifies which printer.
  6. The values corresponding to a margin and page length must be valid integer expressions.
  7. The margins can be defined in any order, but a comma "," is required to separate two page dimensions statements.
  8. The comma "," cannot appear before the first or after the last page dimensions statements.
  9. m-left is the left margin in number of characters.
  10. m-right is the right margin in number of characters.
  11. m-top is the top margin in number of lines.
  12. m-bottom is the bottom margin in number of lines.
  13. p-top is a string that defines the page-eject character sequence.

Tips:

  1. The START REPORT statement is handy to dynamically set up the destination and / or page setup of a report.

Warnings:

  1. If a START REPORT statement references a report that is already running, the report is reinitialized; any output might be unpredictable.

OUTPUT TO REPORT

Syntax:

OUTPUT TO REPORT report-name ( parameters )

Notes:

  1. report-name is the name of the report to which the parameters should be sent.
  2. parameters is the data that needs to be sent to the report. As in a function call, parameters must match the DEFINE section of the report routine.

Warnings:

  1. At compile time, the number of parameters is not checked against the DEFINE section of the report routine. This is a known behavior of the language.

FINISH REPORT

Syntax:

FINISH REPORT report-name

Notes:

  1. report-name is the name of the report to be ended.
  2. FINISH REPORT must be the last statement in the report driver.

Usage:

FINISH REPORT closes the report driver. Therefore, it must be the last statement in the report driver and must follow a START REPORT statement that specifies the name of the same report.

FINISH REPORT does the following:

  1. Completes the second pass, if report is a two-pass report. These 'second pass' activities handle the calculation and output of any aggregate values that are based on all the input records in the report, such as COUNT(*) or PERCENT(*) with no GROUP qualifier.
  2. Executes any AFTER GROUP OF control blocks.
  3. Executes any PAGE HEADER, ON LAST ROW, and PAGE TRAILER control blocks to complete the report.
  4. Copies data from the output buffers of the report to the destination.
  5. Closes the Select cursor on any temporary table that was created to order the input records or to perform aggregate calculations.

TERMINATE REPORT

Syntax:

TERMINATE REPORT report-name

Notes:

  1. report-name is the name of the report to be canceled.

Usage:

TERMINATE REPORT cancels the report processing. It is typically used when the program (or the user) becomes aware that a problem prevents the report from producing part of its intended output, or when the user interrupted the report processing.

TERMINATE REPORT has the following effects:

The EXIT REPORT instruction has the same effect, except that it can be used inside the report definition.


Report Definition

Syntax:

REPORT report-name (argument-list)
    [ define-section  ]
    [ output-section  ]
    [ sort-section ]
    [ format-section  ]
END REPORT

where define-section is a function parameter definition using the DEFINE instruction. You usually define one or more record variables:

DEFINE variable RECORD
           member data-type
          
[,...]
      
END RECORD

where output-section is:

OUTPUT 
[
  REPORT TO
  {
      SCREEN
    | PRINTER
    | [ FILE ] filename
    | PIPE [ IN FORM MODE | IN LINE MODE ] program  
  }
]
[
  [ WITH ]
  [ LEFT MARGIN m-left ] 
  [ RIGHT MARGIN m-right ] 
  [ TOP MARGIN m-top ] 
  [ BOTTOM MARGIN m-bottom ] 
  [ PAGE LENGTH m-length ] 
  [ TOP OF PAGE c-top ] 
]

where sort-section is:

ORDER [ EXTERNAL ] BY variable-list

where format-section is:

FORMAT EVERY ROW

or:

FORMAT
{
 [ FIRST ] PAGE HEADER
 |  ON EVERY ROW
 | BEFORE GROUP OF variable
 | AFTER GROUP OF variable
 | PAGE TRAILER
 |  ON LAST ROW
} 
      [ fgl-statement | sql-statement | report-statement ]
      [...]
   [...]

Notes:

  1. The define-section declares the data types of local variables used within the report, and of any variables (the input records) that are passed as arguments to the report by the calling statement. Reports without arguments or local variables do not require a DEFINE section.
  2. The output-section can set margin and page size values, and can also specify where to send the formatted output. Output from the report consists of successive pages, each containing a fixed number of lines whose margins and maximum number of characters are fixed.
  3. The sort-section specifies how the rows have to be sorted. The specified sort order determines the order in which the runtime system processes any GROUP OF control blocks in the FORMAT section.
  4. The format-section is required. It specifies the appearance of the report, including page headers, page trailers, and aggregate functions of the data. It can also contain control blocks that specify actions to take before or after specific groups of rows are processed. (Alternatively, it can produce a default report by only specifying FORMAT EVERY ROW).

Usage:

The report definition formats input records. Like the FUNCTION or MAIN statement, it is a program block that can be the scope of local variables. It is not, however, a function; it is not reentrant, and CALL cannot invoke it. The report definition receives data from its driver in sets called input records. These records can include program records, but other data types are also supported. Each input record is formatted and printed as specified by control blocks and statements within the report definition. Most statements and functions can be included in a report definition, and certain specialized statements and operators for formatting output can appear only in a report definition.

Like MAIN or FUNCTION, the report definition must appear outside any other program block. It must begin with the REPORT statement and must end with the END REPORT keywords.

Some statements are prohibited in a REPORT program control block.


The DEFINE Section

Syntax:

See the DEFINE statement.

Usage:

This section declares a data type for each formal argument in the REPORT prototype and for any additional local variables that can be referenced only within the REPORT program block. The DEFINE section is required if you pass arguments to the report or if you reference local variables in the report.

For declaring local variables, the same rules apply to the DEFINE section as to the DEFINE statement in MAIN and FUNCTION program blocks. Two exceptions, however, restrict the data types of formal arguments:

Data types of local variables that are not formal arguments are unrestricted. You must include arguments in the report prototype and declare them in the DEFINE section, if any of the following conditions is true:

Aggregates dependent on all records include:

If your report calls an aggregate function, an error might result if any argument of an aggregate function is not also a format argument of the report. You can, however, use global or module variables as arguments of aggregates if the value of the variable does not change while the report is executing.

A report can reference variables of global or module scope that are not declared in the DEFINE section. Their values can be printed, but they can cause problems in aggregates and in BEFORE GROUP OF and AFTER GROUP OF clauses. Any references to non-local variables can produce unexpected results, however, if their values change while a two-pass report is executing.


The OUTPUT Section

Syntax:

OUTPUT 
[
  REPORT TO
  {
      SCREEN
    | PRINTER
    | [ FILE ] filename
    | PIPE [ IN FORM MODE | IN LINE MODE ] program  
  }
]
[
  [ WITH ]
  [ LEFT MARGIN m-left ] 
  [ RIGHT MARGIN m-right ] 
  [ TOP MARGIN m-top ] 
  [ BOTTOM MARGIN m-bottom ] 
  [ PAGE LENGTH m-length ] 
  [ TOP OF PAGE c-top ] 
]

Notes:

  1. This section is superseded by any corresponding START REPORT specifications. Any output destination or page setup definition may be overridden by the report driver with the START REPORT instruction.
  2. program is a string literal, global, or constant specifying the name of a program, shell script, command receiving the output.
  3. filename is a string literal, global, or constant specifying the file which receives the output of the report.
  4. m-left is the left margin in number of characters.
  5. m-right is the right margin in number of characters.
  6. m-top is the top margin in number of lines.
  7. m-bottom is an integer the bottom margin in number of lines.
  8. p-top is a string that defines the page-eject character sequence.

Usage:

The OUTPUT section can specify the destination and dimensions for output from the report and the page-eject sequence for the printer. If you omit the OUTPUT section, the report uses default values to format each page. This section is superseded by any corresponding START REPORT specifications.

The OUTPUT section can direct the output from the report to a printer, file, or pipe, and can initialize the page dimensions and margins of report output. If PRINTER is specified, the DBPRINT environment variable specifies which printer.

The START REPORT statement of the report driver can override all of these specifications by assigning another destination in its TO clause or by assigning other dimensions, margins, or another page-eject sequence in the WITH clause.

Because the size specifications for the dimensions and margins of a page of report output that the OUTPUT section can specify must be literal integers, you might prefer to reset these values in the START REPORT statement, where you can use variables to assign these values dynamically at runtime.


The ORDER BY Section

Purpose:

This section specifies how the variables of the input records are to be sorted. It is required if the report driver does not send sorted data to the report. The specified sort order determines the order in which the runtime system processes any GROUP OF control blocks in the FORMAT section.

Syntax:

ORDER [ EXTERNAL ] BY variable-list

Notes:

  1. variable-list  is a list of names representing defined variables, without the DEFINE keyword and without the data type.
  2. The EXTERNAL keyword specifies that the data is sent to the report in a sorted order. Without the EXTERNAL keyword, the report driver sorts the data before sending it to the report program block.

Usage:

The ORDER BY section specifies a sort list for the input records. Include this section if values that the report definition receives from the report driver are significant in determining how BEFORE GROUP OF or AFTER GROUP OF control blocks will process the data in the formatted report output.

If you omit the ORDER BY section, the runtime system processes input records in the order received from the report driver and processes any GROUP OF control blocks in their order of appearance in the FORMAT section. If records are not sorted in the report driver, the GROUP OF control blocks might be executed at random intervals (that is, after any input record) because unsorted values tend to change from record to record.

If you specify only one variable in the GROUP OF control blocks, and the input records are already sorted in sequence on that variable by the SELECT statement, you do not need to include an ORDER BY section in the report.

Specify ORDER EXTERNAL BY if the input records have already been sorted by the SELECT statement. The list of variables after the keywords ORDER EXTERNAL BY control the execution order of GROUP BY control blocks.

Without the EXTERNAL keyword, the report is a two-pass report, meaning that the report engine processes the set of input records twice. During the first pass, the report engine sorts the data and stores the sorted values in a temporary file in the database. During the second pass, it calculates any aggregate values and produces output from data in the temporary files.

With the EXTERNAL keyword, the report engine only needs to make a single pass through the data: it does not need to build the temporary table in the database for sorting the data. Specifying EXTERNAL to instruct the report engine not to sort the records again might result in an improvement in performance.


The FORMAT Section

Purpose:

A report definition must contain a FORMAT section. The FORMAT section determines how the output from the report will look. It works with the values that are passed to the REPORT program block through the argument list or with global or module variables in each record of the report. In a source file, the FORMAT section begins with the FORMAT keyword and ends with the END REPORT keywords.

Syntax:

Default format:

FORMAT EVERY ROW

Custom format:

FORMAT
   control-block
      [ fgl-statement | sql-statement | report-statement ]
      [...]
    [...]

where control-block can be one of:

{
[ FIRST ] PAGE HEADER
|  ON EVERY ROW
|  BEFORE GROUP OF variable
|  AFTER GROUP OF variable
|  PAGE TRAILER
|  ON LAST ROW
}

Notes:

  1. fgl-statement is any language instruction supported in the report routine.
  2. sql-statement is any SQL statement supported by the language.
  3. report-statement is any report-specific instruction.

Usage:

The FORMAT section is made up of the following Control Blocks:

If you use the FORMAT EVERY ROW, no other statements or control blocks are valid. The EVERY ROW keywords specify a default output format, including every input record that is passed to the report.

Control blocks define the structure of a report by specifying one or more statements to be executed when specific parts of the report are processed.

If a report driver includes START REPORT and FINISH REPORT statements, but no data records are passed to the report, no control blocks are executed. That is, unless the report executes an OUTPUT TO REPORT statement that passes at least one input record to the report; then neither the FIRST PAGE HEADER control block nor any other control block is executed

Apart from BEFORE GROUP OF and AFTER GROUP OF, each control block must appear only one time.

More complex FORMAT sections can contain control blocks like ON EVERY ROW or BEFORE GROUP OF, which contain statements to execute while the report is being processed. Control blocks can contain report execution statements and other executable statements.

See also statements and report format section.

A control block may invoke most fgl-statements and sql-statements, except those listed in prohibited statements.

The BEFORE/AFTER GROUP OF control blocks can include aggregate functions to instruct the report engine to automatically compute such values.

A report-statement is a statement specially designed for the report format section. It cannot be used in any other part of the program.

The sequence in which the BEFORE GROUP OF and AFTER GROUP OF control blocks are executed depends on the sort list in the ORDER BY section, regardless of the physical sequence in which these control blocks appear within the FORMAT section.


FORMAT EVERY ROW

A report routine written with FORMAT EVERY ROW formats the report in a simple default format, containing only the values that are passed to the REPORT program block through its arguments, and the names of the arguments. You cannot modify the EVERY ROW statement with any of the statements listed in report execution statements, and neither can you include any control blocks in the FORMAT section.

The report engine uses as column headings the names of the variables that the report driver passes as arguments at runtime. If all fields of each input record can fit horizontally on a single line, the default report prints the names across the top of each page and the values beneath. Otherwise, it formats the report with the names down the left side of the page and the values to the right, as in the previous example. When a variable contains a null value, the default report prints only the name of the variable, with nothing for the value.

The following example is a brief report specification that uses FORMAT EVERY ROW. We assume here that the cursor that retrieved the input records for this report was declared with an ORDER BY clause, so that no ORDER BY section is needed in this report definition:

01 DATABASE stores7
02
03 REPORT simple( order_num, customer_num, order_date )
04
05   DEFINE order_num LIKE orders.order_num,
06         customer_num LIKE orders.customer_num,
07         order_date LIKE orders.order_date
08
09   FORMAT EVERY ROW
10
11 END REPORT

The above example would produce the following output:

order_num customer_num order_date
     1001         104  01/20/1993
     1002         101  06/01/1993
     1003         104  10/12/1993
     1004         106  04/12/1993
     1005         116  12/04/1993
     1006         112  09/19/1993
     1007         117  03/25/1993
     1008         110  11/17/1993
     1009         111  02/14/1993
     1010         115  05/29/1993
     1011         104  03/23/1993
     1012         117  06/05/1993

FIRST PAGE HEADER

This control block specifies the action that the runtime system takes before it begins processing the first input record. You can use it, for example, to specify what appears near the top of the first page of output from the report.

Because the runtime system executes the FIRST PAGE HEADER control block before generating any output, you can use this control block to initialize variables that you use in the FORMAT section.

If a report driver includes START REPORT and FINISH REPORT statements, but no data records are passed to the report, this control block is not executed. That is, unless the report executes an OUTPUT TO REPORT statement that passes at least one input record to the report, neither the FIRST PAGE HEADER control block nor any other control block is executed.

As its name implies, you can also use a FIRST PAGE HEADER control block to produce a title page as well as column headings. On the first page of a report, this control block overrides any PAGE HEADER control block. That is, if both a FIRST PAGE HEADER and a PAGE HEADER control block exist, output from the first appears at the beginning of the first page, and output from the second begins all subsequent pages.

The TOP MARGIN (set in the OUTPUT section) determines how close the header appears to the top of the page.

Warnings:

  1. You cannot include a SKIP integer LINES statement inside a loop within this control block.
  2. The NEED statement is not valid within this control block.
  3. If you use an IFTHENELSE statement within this control block, the number of lines displayed by any PRINT statements following the THEN keyword must be equal to the number of lines displayed by any PRINT statements following the ELSE keyword.
  4. If you use a CASE, FOR, or WHILE statement that contains a PRINT statement within this control block, you must terminate the PRINT statement with a semicolon ( ; ). The semicolon suppresses any LINEFEED characters in the loop, keeping the number of lines in the header constant from page to page.
  5. You cannot use a PRINT filename statement to read and display text from a file within this control block

Corresponding restrictions also apply to CASE, FOR, IF, NEED, SKIP, PRINT, and WHILE statements in PAGE HEADER and PAGE TRAILER control blocks.


PAGE HEADER

This control block is executed whenever a new page is added to the report. The PAGE HEADER control block specifies the action that the runtime takes before it begins processing each page of the report. It can specify what information, if any, appears at the top of each new page of output from the report.

The TOP MARGIN specification (in the OUTPUT section) affects how many blank lines appear above the output produced by statements in the PAGE HEADER control block.

You can use the PAGENO operator in a PRINT statement within a PAGE HEADER control block to automatically display the current page number at the top of every page.

The FIRST PAGE HEADER control block overrides this control block on the first page of a report.

New group values can appear in the PAGE HEADER control block when this control block is executed after a simultaneous end-of-group and end-of-page situation.

The runtime system delays the processing of the PAGE HEADER control block until it encounters the first PRINT, SKIP, or NEED statement in the ON EVERY ROW, BEFORE GROUP OF, or AFTER GROUP OF control block. This order guarantees that any group columns printed in the PAGE HEADER control block have the same values as the columns printed in the ON EVERY ROW control block.

Warnings:

  1. Warnings that apply to FIRST PAGE HEADER also apply to PAGE HEADER

PAGE TRAILER

The PAGE TRAILER control block specifies what information, if any, appears at the bottom of each page of output from the report.

The runtime system executes the statements in the PAGE TRAILER control block before the PAGE HEADER control block when a new page is needed. New pages can be initiated by any of the following conditions:

You can use the PAGENO operator in a PRINT statement within a PAGE TRAILER control block to automatically display the page number at the bottom of every page, as in the following example:

01 PAGE TRAILER
02    PRINT COLUMN 28, PAGENO USING "page <<<<"

The BOTTOM MARGIN specification (in the OUTPUT section) affects how close to the bottom of the page the output displays the page trailer.

Warnings:

  1. Warnings that apply to FIRST PAGE HEADER also apply to PAGE TRAILER

BEFORE/AFTER GROUP OF

The BEFORE/AFTER GROUP OF control blocks specify what action the runtime system takes respectively before or after it processes a group of input records. Group hierarchy is determined by the ORDER BY specification in the SELECT statement or in the report definition.

A group of records is all of the input records that contain the same value for the variable whose name follows the AFTER GROUP OF keywords. This group variable must be passed through the report arguments. A report can include no more than one AFTER GROUP OF control block for any group variable.

When the runtime system executes the statements in a BEFORE/AFTER GROUP OF control block, the report variables have the values from the first / last record of the new group. From this perspective, the BEFORE/AFTER GROUP OF control block could be thought of as the "on first / last record of group" control block.

Each BEFORE GROUP OF block is executed in order, from highest to lowest priority, at the start of a report (after any FIRST PAGE HEADER or PAGE HEADER control blocks, but before processing the first record) and on these occasions:

The runtime system executes the AFTER GROUP OF control block on these occasions:

How often the value of the group variable changes depends in part on whether the input records have been sorted by the SELECT statement:

You can sort the records by specifying a sort list in either of the following areas:

To sort data in the report definition (with an ORDER BY section), make sure that the name of the group variable appears in both the ORDER BY section and in the BEFORE GROUP OF control block.

To sort data in the ORDER BY clause of a SELECT statement, perform the following tasks:

If you specify sort lists in both the report driver and the report definition, the sort list in the ORDER BY section of the REPORT takes precedence.
When the runtime system starts to generate a report, it first executes the BEFORE GROUP OF control blocks in descending order of priority before it executes the ON EVERY ROW control block. If the report is not already at the top of the page, the SKIP TO TOP OF PAGE statement in a BEFORE GROUP OF control block causes the output for each group to start at the top of a page.

If the sort list includes more than one variable, the runtime system sorts the records by values in the first variable (highest priority). Records that have the same value for the first variable are then ordered by the second variable and so on until records that have the same values for all other variables are ordered by the last variable (lowest priority) in the sort list.

The ORDER BY section determines the order in which the runtime system processes BEFORE GROUP OF and AFTER GROUP OF control blocks. If you omit the ORDER BY section, the runtime system processes any GROUP OF control blocks in the lexical order of their appearance within the FORMAT section.

If you include an ORDER BY section, and the FORMAT section contains more than one BEFORE GROUP OF or AFTER GROUP OF control block, the order in which these control blocks are executed is determined by the sort list in the ORDER BY section. In this case, their order within the FORMAT section is not significant because the sort list overrides their lexical order.

The runtime system processes all the statements in a BEFORE GROUP OF or AFTER GROUP OF control block on these occasions:

In the AFTER GROUP OF control block, you can include the GROUP keyword to qualify aggregate report functions like AVG(), SUM(), MIN(), or MAX():

01  AFTER GROUP OF r.order_num
02    PRINT r.order_date, 7 SPACES,
03         r.order_num USING"###&", 8 SPACES,
04         r.ship_date, " ",
05         GROUP SUM(r.total_price) USING"$$$$,$$$,$$$.&&"
06  AFTER GROUP OF r.customer_num
07    PRINT 42 SPACES, "-------------------"
08    PRINT 42 SPACES, GROUP SUM(r.total_price) USING"$$$$,$$$,$$$.&&"

Using the GROUP keyword to qualify an aggregate function is only valid within the AFTER GROUP OF control block. It is not valid, for example, in the BEFORE GROUP OF control block.

After the last input record is processed, the runtime system executes the AFTER GROUP OF control blocks before it executes the ON LAST ROW control block.


ON EVERY ROW

The ON EVERY ROW control block specifies the action to be taken by the runtime system for every input record that is passed to the report definition.

The runtime system executes the statements within the ON EVERY ROW control block for each new input record that is passed to the report. The following example is from a report that lists all the customers, their addresses, and their telephone numbers across the page:

01  ON EVERY ROW
02    PRINT r.fname, " ", r.lname, " ",
03         r.address1, " ", r.cust_phone

The runtime system delays processing the PAGE HEADER control block (or the FIRST PAGE HEADER control block, if it exists) until it encounters the first PRINT, SKIP, or NEED statement in the ON EVERY ROW control block.

If a BEFORE GROUP OF control block is triggered by a change in the value of a variable, the runtime system executes all appropriate BEFORE GROUP OF control blocks (in the order of their priority) before it executes the ON EVERY ROW control block. Similarly, if execution of an AFTER GROUP OF control block is triggered by a change in the value of a variable, the runtime system executes all appropriate AFTER GROUP OF control blocks (in the reverse order of their priority) before it executes the ON EVERY ROW control block.


ON LAST ROW

The ON LAST ROW control block specifies the action that the runtime system is to take after it processes the last input record that was passed to the report definition and encounters the FINISH REPORT statement.

The statements in the ON LAST ROW control block are executed after the statements in the ON EVERY ROW and AFTER GROUP OF control blocks if these blocks are present.

When the runtime system processes the statements in an ON LAST ROW control block, the variables that the report is processing still have the values from the final record that the report processed. The ON LAST ROW control block can use aggregate functions to display report totals.


Statements in Report Definition Routine

Prohibited Statements

Language statements that have no meaning inside a report definition routine are prohibited. The following table shows some of the statements that are not valid within any control block of the FORMAT section of a REPORT program block:

CONSTRUCT FUNCTION MENU
DEFER INPUT PROMPT
DEFINE INPUT ARRAY REPORT
DISPLAY ARRAY MAIN RETURN

A compile-time error is issued if you attempt to include any of these statements in a control block of a report. You can call a function that includes some of these statements, but this is not recommended.

Report Control Statements

The following statements can appear only in control blocks of the FORMAT section of a report definition:

Statement Effect
EXIT REPORT Cancels processing of the report from within the report definition.
NEED Forces a page break unless some specified number of lines is available on the current page of the report.
PAUSE Allows the user to control scrolling of screen output (This statement has no effect if output is sent to any destination except the screen.)
PRINT Appends a specified item to the output of the report.
SKIP Inserts blank lines into a report or forces a page break.

The Report Prototype

When defining a report routine, the report name must immediately follow the REPORT keyword. The name must be unique among function and report names within the program. Its scope is the entire program.

The list of formal arguments of the report must be enclosed in parentheses and separated by commas. These are local variables that store values that the calling routine passes to the report. The compiler issues an error unless you declare their data types in the subsequent DEFINE section. You can include a program record in the formal argument list, but you cannot append the .* symbols to the name of the record. Arguments can be of any data type except ARRAY, or a record with an ARRAY member.

When you call a report, the formal arguments are assigned values from the argument list of the OUTPUT TO REPORT statement. These actual arguments that you pass must match, in number and position, the formal arguments of the REPORT routine. The data types must be compatible, but they need not be identical. The runtime system can perform some conversions between compatible data types.

The names of the actual arguments and the formal arguments do not have to match.

You must include the following items in the list of formal arguments:


Two-Pass Reports

The report engine supports one-pass reports and two-pass reports. The one-pass report requires sorted data to be produced by the report driver in order to handle before/after groups properly. The two-pass report handles sorts internally and does not need sorted data from the report driver. During the first pass, the report engine sorts the data and stores the sorted values in a temporary file in the database. During the second pass, it calculates any aggregate values and produces output from data in the temporary files.

A report is defined as a two-pass report if it includes any of the following items:

Two-pass reports create temporary tables. The FINISH REPORT statement uses values from these tables to calculate any global aggregates, and then deletes the tables.

Warnings:

  1. A two-pass report is one that creates a temporary table. Therefore, the report engine requires that the program be connected to a database when the report runs. Make sure that the database server and the database driver supports temporary table creation and indexes creation on temporary tables.

Report Instructions

EXIT REPORT

Syntax:

EXIT REPORT

Usage:

EXIT REPORT cancels the report processing. It must appear in the FORMAT section of the report definition. It is useful after the program (or the user) becomes aware that a problem prevents the report from producing part of its intended output.

EXIT REPORT has the following effects:

You cannot use the RETURN statement as a substitute for EXIT REPORT. An error is issued if RETURN is encountered within the definition of a report.


PRINT

Syntax:

PRINT
 { 
    expression
  | COLUMN left-offset
  | PAGENO
  | LINENO
  | ns SPACES
  | [GROUP] COUNT(*) [ WHERE condition ]
  | [GROUP] PERCENT(*) [ WHERE condition ]
  | [GROUP] AVG( variable ) [ WHERE condition ]
  | [GROUP] SUM( variable ) [ WHERE condition ]
  | [GROUP] MIN( variable ) [ WHERE condition ]
  | [GROUP] MAX( variable ) [ WHERE condition ]
  | char-expression WORDWRAP [ RIGHT MARGIN rm ]
  | FILE "file-name"
 } [,...]
  [ ; ]

Notes:

  1. expression is any legal language expression.
  2. left-offset is described in COLUMN.
  3. ns is described in SPACES.
  4. char-expression is a string expression or a TEXT variable.
  5. file-name is a string expression, or a quoted string, that specifies the name of a text file to include in the output from the report.

Warnings:

  1. You cannot use PRINT to display a BYTE value. The string "<byte value>" is the only output from PRINT of any object that is not of the TEXT data type.

Usage:

This statement can include character data in the form of an ASCII file, a TEXT variable, or a comma-separated expression list of character expressions in the output of the report. (For TEXT variable or filename, you cannot specify additional output in the same PRINT statement.) You cannot display a BYTE value. Unless its scope of reference is global or the current module, any program variable in expression list must be declared in the DEFINE section.

The PRINT FILE statement reads the contents of the specified filename into the report, beginning at the current character position. This statement permits you to insert a multiple-line character string into the output of a report. If file-name stores the value of a TEXT variable, the PRINT FILE file-name statement has the same effect as specifying PRINT text-variable. (But only PRINT variable can include the WORDWRAP operator)

PRINT statement output begins at the current character position, sometimes called simply the current position. On each page of a report, the initial default character position is the first character position in the first line. This position can be offset horizontally and vertically by margin and header specifications and by executing any of the following statements:

Unless you use the keyword CLIPPED or USING, values are displayed with widths (including any sign) that depend on their declared data types.

Data Type Default Print With
BYTE N/A
CHAR Length of character data type declaration.
DATE DBDATE dependant, 10 if DBDATE = "MDY4/"
DATETIME From 2 to 25, as implied in the data type declaration.
DECIMAL (2 + p + s), where p is the precision and s is the scale from the data type declaration.
FLOAT 14
INTEGER 11
INTERVAL From 3 to 25, as implied in the data type declaration.
MONEY (2 + c + p + s), where c is the length of the currency defined by DBMONEY and p is the precision and s is the sacle from the data type declaration.
NCHAR Length of character data type declaration.
NVARCHAR Length current value in the variable.
SMALLFLOAT 14
SMALLINT 6
STRING Length current value in the variable.
TEXT Length current value in the variable.
VARCHAR Length current value in the variable.

Unless you specify the FILE or WORDWRAP option, each PRINT statement displays output on a single line. For example, this fragment displays output on two lines:

01  PRINT fname, lname
02  PRINT city, ", ", state, " ", zipcode

If you terminate a PRINT statement with a semicolon, however, you suppress the implicit LINEFEED character at the end of the line. The next example has the same effect as the PRINT statements in the previous example:

01  PRINT fname;
02  PRINT lname
03  PRINT city, ", ", state, " ", zipcode

The expression list of a PRINT statement returns one or more values that can be displayed as printable characters. The expression list can contain report variables, built-in functions and operators. Some of these can appear only in a REPORT program block such as PAGENO, LINENO, PERCENT.

If the expression list applies the USING operator to format a DATE or MONEY value, the format string of the USING operator takes precedence over the DBDATE, DBMONEY, and DBFORMAT environment variables.

Aggregate report functions summarize data from several records in a report. The syntax and effects of aggregates in a report resemble those of SQL aggregate functions but are not identical.

The expression (in parentheses) that SUM( ), AVG( ), MIN( ), or MAX( ) takes as an argument is typically of a number or INTERVAL data type; ARRAY, BYTE, RECORD, and TEXT are not valid. The SUM( ), AVG( ), MIN( ), and MAX( ) aggregates ignore input records for which their arguments have null values, but each returns NULL if every record has a null value for the argument.

The GROUP keyword is an optional keyword that causes the aggregate function to include data only for a group of records that have the same value for a variable that you specify in an AFTER GROUP OF control block. An aggregate function can only include the GROUP keyword within an AFTER GROUP OF control block.

The optional WHERE clause allows you to select among records passed to the report, so that only records for which the Boolean expression is TRUE are included.

Example:

The following example is from the FORMAT section of a report definition that displays both quoted strings and values from rows of the customer table:

01  FIRST PAGE HEADER
02     PRINT COLUMN 30, "CUSTOMER LIST"
03     SKIP 2 LINES
04     PRINT "Listings for the State of ", thisstate
05  SKIP 2 LINES
06     PRINT "NUMBER", COLUMN 12, "NAME", COLUMN 35, "LOCATION",
07           COLUMN 57, "ZIP", COLUMN 65, "PHONE"
08     SKIP 1 LINE
09  PAGE HEADER
10     PRINT "NUMBER", COLUMN 12, "NAME", COLUMN 35, "LOCATION",
11            COLUMN 57, "ZIP", COLUMN 65, "PHONE"
12     SKIP 1 LINE
13  ON EVERY ROW
14     PRINT customer_num USING "###&", COLUMN 12, fname CLIPPED,
15          1 SPACE, lname CLIPPED, COLUMN 35, city CLIPPED, ", ",
16          state, COLUMN 57, zipcode, COLUMN 65, phone

NEED

Syntax:

NEED n LINE[S]

Notes:

  1. n is the number of lines.

Usage:

This statement has the effect of a conditional SKIP TO TOP OF PAGE statement, the condition being that the number to which the integer expression evaluates is greater than the number of lines that remain on the current page.

The NEED statement can prevent the report from dividing parts of the output that you want to keep together on a single page. In the following example, the NEED statement causes the PRINT statement to send output to the next page unless at least six lines remain on the current page:

01  AFTER GROUP OF r.order_num
02    NEED 6 LINES
03    PRINT " ", r.order_date, "  ", GROUP SUM(r.total_price)

The LINES value specifies how many lines must remain between the line above the current character position and the bottom margin for the next PRINT statement to produce output on the current page. If fewer than LINES remain on the page, the report engine prints both the PAGE TRAILER and the PAGE HEADER.

The NEED statement does not include the BOTTOM MARGIN value when it compares LINES to the number of lines remaining on the current page. NEED is not valid in FIRST PAGE HEADER, PAGE HEADER, or PAGE TRAILER blocks.


PAUSE Console Only!

Syntax:

PAUSE [ "comment" ]

Notes:

  1. comment is an optional comment to be displayed.

Usage:

Output is sent by default to the screen unless the START REPORT statement or the OUTPUT section specifies a destination for report output.

The PAUSE statement can be executed only if the report sends its output to the screen. It has no effect if you include a TO clause in either of these contexts:

Include the PAUSE statement in the PAGE HEADER or PAGE TRAILER block of the report. For example, the following code causes the runtime system to skip a line and pause at the end of each page of report output displayed on the screen:

01  PAGE TRAILER
02    SKIP 1 LINE
03    PAUSE "Press return to continue"

SKIP

Syntax:

SKIP { n LINE[S] | TO TOP OF PAGE }

Notes:

  1. n is the number of lines.
  2. The LINE and LINES keywords are synonyms in the SKIP statement.

Warnings:

  1. The SKIP n LINES statement cannot appear within a CASE statement, a FOR loop, or a WHILE loop.
  2. The SKIP TO TOP OF PAGE statement cannot appear in a FIRST PAGE HEADER, PAGE HEADER or PAGE TRAILER control block.

Usage:

The SKIP statement allows you to insert blank lines into report output or to skip to the top of the next page as if you had included an equivalent number of PRINT statements without specifying any expression list.

Output from any PAGE HEADER or PAGE TRAILER control block appears in its usual location.

Example:

01  FIRST PAGE HEADER
02    PRINT "Customer List"
03    SKIP 2 LINES
04    PRINT "Number        Name               Location"
05    SKIP 1 LINE
06  PAGE HEADER
07    PRINT "Number        Name               Location"
08    SKIP 1 LINE
09  ON EVERY ROW
10    PRINT r.customer_num, r.fname, r.city

Report Operators

COLUMN

Syntax:

COLUMN p

Notes:

  1. p is the column position (starts at 1).

Usage:

COLUMN specifies the position in the current line of a report where output of the next value in a PRINT statement begins.

The COLUMN operator can appear in PRINT statements to move the character position forward within the current line.

The operand must be a non-negative integer that specifies a character position offset (from the left margin) no greater than the line width (that is, no greater than the difference (right margin - left margin). This designation moves the character position to a left-offset, where 1 is the first position after the left margin. If current position is greater than the operand, the COLUMN specification is ignored.

Example:

01  FIRST PAGE HEADER
02    PRINT "Customer List"
03    PRINT "Number", COLUMN 12,"Name", COLUMN 35,"Location"
04  PAGE HEADER
05    PRINT "Number", COLUMN 12,"Name", COLUMN 35,"Location"
06  ON EVERY ROW
07    PRINT customer_num, COLUMN 12,fname, COLUMN 35,city

LINENO

Syntax:

LINENO

Usage:

This operator takes no operand but returns the value of the line number of the report line that is currently printing. The report engine calculates the line number by calculating the number of lines from the top of the current page, including the TOP MARGIN.

Example:

In the following example, a PRINT statement instructs the report to calculate and display the current line number, beginning in the tenth character position after the left margin:

01  ON EVERY ROW
02    IF LINENO > 9 THEN
03      PRINT COLUMN 10, "Line:", LINENO USING "<<<"
04    END IF

PAGENO

Syntax:

PAGENO

Usage:

This operator takes no operand but returns the number of the page the report engine is currently printing.

You can use PAGENO in the PAGE HEADER or PAGE TRAILER block, or in other control blocks to number the pages of a report sequentially.

Example:

If you use the SQL aggregate COUNT(*) in the SELECT statement to find how many records are returned by the query, and if the number of records that appear on each page of output is both fixed and known, you can calculate the total number of pages, as in the following example:

01  FIRST PAGE HEADER
02    SELECT COUNT(*) INTO cnt FROM customer
03    LET y = cnt/50 -- Assumes 50 records per page
04  ON EVERY ROW
05    PRINT COLUMN 10, r.customer_num, ...
06  PAGE TRAILER
07    PRINT PAGE PAGENO USING "<<" OF cnt USING "<<"

If the calculated number of pages was 20, the first page trailer would be:

Page 1 of 20

PAGENO is incremented with each page, so the last page trailer would be:

Page 20 of 20


SPACES

Syntax:

n SPACES

Notes:

  1. n is the number of spaces.

Usage:

This operator returns a string of blanks, equivalent to a quoted string containing the specified number of blanks.

In a PRINT statement, these blanks are inserted at the current character position.

Its operand must be an integer expression that returns a positive number, specifying an offset (from the current character position) no greater than the difference (right margin - current position). After PRINT SPACES has executed, the new current character position has moved to the right by the specified number of characters.

Outside PRINT statements, SPACES and its operand must appear within parentheses: (n SPACES).

Example:

01 ON EVERY ROW
02    LET s = (6 SPACES), "=ZIP"
03    PRINT r.fname, 2 SPACES, r.lname, s

WORDWRAP

Syntax:

WORDWRAP [ RIGHT MARGIN tm ]

Notes:

  1. tm defines the temporary right margin.

Usage:

The WORDWRAP operator automatically wraps successive segments of long character strings onto successive lines of report output. Any string value that is too long to fit between the current position and the right margin is divided into segments and displayed between temporary margins:

Specify WORDWRAP RIGHT MARGIN tm  to set a temporary right margin, counting from the left edge of the page. This value cannot be smaller than the current character position or greater than right margin defined for the report. The current character position becomes the temporary left margin. These temporary values override the specified or default left and right margins of the report.

After the PRINT statement has executed, any explicit or default margins defined in the RIGHT MARGIN clause of the OUTPUT section or START REPORT instruction are restored.

The following PRINT statement specifies a temporary left margin in column 10 and a temporary right margin in column 70 to display the character string that is stored in the variable called mynovel:

01  PRINT COLUMN 10, mynovel WORDWRAP RIGHT MARGIN 70 

The data string can include printable ASCII characters. It can also include the TAB (ASCII 9), LINEFEED (ASCII 10), and ENTER (ASCII 13) characters to partition the string into words that consist of sub-strings of other printable characters. Other nonprintable characters might cause runtime errors. If the data string cannot fit between the margins of the current line, the report engine breaks the line at a word division, and pads the line with blanks at the right.

From left to right, the report engine expands any TAB character to enough blank spaces to reach the next tab stop. By default, tab stops are in every eighth column, beginning at the left-hand edge of the page. If the next tab stop or a string of blank characters extends beyond the right margin, the report engine takes these actions:

  1. Prints blank characters only to the right margin.
  2. Discards any remaining blanks from the blank string or tab.
  3. Starts a new line at the temporary left margin.
  4. Processes the next word.

The report engine starts a new line when a word plus the next blank space cannot fit on the current line. If all words are separated by a single space, this action creates an even left margin. The following rules are applied (in descending order of precedence) to the portion of the data string within the right margin:

The report engine maintains page discipline under the WORDWRAP option. If the string is too long for the current page, the report engine executes the statements in any page trailer and header control blocks before continuing output onto a new page.

For Japanese locales, a suitable break can also be made between the Japanese characters. However, certain characters must not begin a new line, and some characters must not end a line. This convention creates the need for KINSOKU processing, whose purpose is to format the line properly, without any prohibited word at the beginning or ending of a line.

Reports use the wrap-down method for WORDWRAP and KINSOKU processing. The wrap-down method forces down to the next line characters that are prohibited from ending a line. A character that precedes another that is prohibited from beginning a line can also wrap down to the next line. Characters that are prohibited from beginning or ending a line must be listed in the locale. 4GL tests for prohibited characters at the beginning and ending of a line, testing the first and last visible characters. The KINSOKU processing only happens once for each line. That is, no further KINSOKU processing occurs, even if prohibited characters are still on the same line after the first KINSOKU processing.


Report Aggregate Functions

COUNT

Syntax:

[GROUP] COUNT(*) [ WHERE condition ]

Usage:

This aggregate returns the total number of records qualified by the optional WHERE condition. 

Warnings:

  1. You must include the (*) symbol.

Example:

The following fragment of a report definition uses the AFTER GROUP OF control block and GROUP keyword to form sets of records according to how many items are in each order. The last PRINT statement calculates the total price of each order, adds a shipping charge, and prints the result. Because no WHERE clause is specified here, GROUP SUM( ) combines the total_price of every item in the group included in the order.

01  AFTER GROUP OF number
02    SKIP 1 LINE
03    PRINT 4 SPACES, "Shipping charges for the order: ",
04          ship_charge USING "$$$$.&&"
05    PRINT 4 SPACES, "Count of small orders: ",
06         GROUP COUNT(*) WHERE total_price < 200.00 USING "##,###"
07    SKIP 1 LINE
08    PRINT 5 SPACES, "Total amount for the order: ",
09          ship_charge + GROUP SUM(total_price) USING "$$,$$$,$$$.&&"

PERCENT

Syntax:

[GROUP] PERCENT(*) [ WHERE condition ]

Usage:

This aggregate returns the percentage of the total number of records qualified by the optional WHERE condition.

Warnings:

  1. You must include the (*) symbol.

SUM

Syntax:

[GROUP] SUM( expression ) [ WHERE condition ]

Usage:

This aggregate evaluates as the total of expression among all records or among records qualified by the optional WHERE clause and any GROUP specification.

Warnings:

  1. If one of the values is NULL, it is ignored.
  2. By default, if all values are NULL, the result of the aggregate is NULL. See also: Report Configuration.

AVG

Syntax:

[GROUP] AVG( expression ) [ WHERE condition ]

Usage:

This aggregate evaluates as the average (that is, the arithmetic mean value) of expression among all records or among records qualified by the optional WHERE clause and any GROUP specification.

Warnings:

  1. If one of the values is NULL, it is ignored.
  2. By default, if all values are NULL, the result of the aggregate is NULL. See also: Report Configuration.

MIN

Syntax:

[GROUP] MIN( expression ) [ WHERE condition ]

Usage:

For number, currency, and interval values, MIN(expression) returns the minimum value for expression among all records or among records qualified by the WHERE clause and any GROUP specification. For DATETIME or DATE data values, greater than means later and less than means earlier in time. Character strings are sorted according to their first character. If your program is executed in the default (U.S. English) locale, for character data types, greater than means after in the ASCII collating sequence, where a> A> 1, and less than means before in the ASCII sequence, where 1< A< a.


MAX

Syntax:

[GROUP] MAX( expression ) [ WHERE condition ]

Usage:

For number, currency, and interval values, MAX(expression) returns the maximum value for expression among all records or among records qualified by the WHERE clause and any GROUP specification. For DATETIME or DATE data values, greater than means later and less than means earlier in time. Character strings are sorted according to their first character. If your program is executed in the default (U.S. English) locale, for character data types, greater than means after in the ASCII collating sequence, where a> A> 1, and less than means before in the ASCII sequence, where 1< A< a.