Present When Clause
This clause places a general COBOL condition on any report entry. By evaluating the condition, report writer determines whether your entry is to be output as normal or skipped.
Present/Absent When Clause: Coding Rules
-
The condition may be any valid COBOL conditional expression. You are not restricted to simple conditions. For example, the following compound condition is quite acceptable:
PRESENT WHEN SALARY > 20000 AND (AGE < 20 OR MARITAL-STATUS = "M" OR "D")
Each of the data items you use in your condition may come from any COBOL SECTION (but see the note Use of Total Fields, if you use SUM fields from the REPORT SECTION itself). You may optionally place parentheses "( )" around the whole conditional expression for clarity. The symbols ">=" (greater than or equal to) and "<=" (less than or equal to) are allowed. For more information, you should refer to your COBOL language reference under conditional expressions, for a list of the many varied ways of forming COBOL conditions.
-
The CONTROL IS control-id form if allowed only if the current group is a multiple CONTROL FOOTING, that is, one with a TYPE CONTROL FOOTING clause with more than one control-id operand, or TYPE CONTROL FOOTING FOR ALL.
-
The keyword PRESENT is implied if omitted. Experience has shown that your code will be clearer if you include the PRESENT keyword in the single form of the clause but omit it in the multiple-choice form described below and in the following example:
-
The keyword ABSENT gives the clause the exact opposite meaning from the same clause with PRESENT; ABSENT WHEN condition is equivalent to PRESENT WHEN NOT (condition). So you may find it more expressive to write:
ABSENT WHEN AGE < 21 AND LOCN = "NY"
rather thanPRESENT WHEN AGE NOT < 21 OR LOCN NOT = "NY".
Whenever we refer to the PRESENT WHEN clause, you can assume that this term includes the ABSENT WHEN form.
-
PRESENT UNLESS is an older syntax, synonymous with ABSENT WHEN.
-
You may write these clauses in any report group entry other than the RD itself. An entry that has a PRESENT WHEN clause is often referred to as a conditional entry. The same field may be subject to any number of PRESENT WHEN clauses at any number of different levels. The following sample group has one of the clauses in all the possible positions:
-
If you nest more than one PRESENT WHEN clause by writing one clause in a higher entry and another in a lower entry beneath it, as in the preceding example, the outer condition takes precedence over the inner condition. It is up to you to ensure that both conditions can be true at the same time. Report writer will not check for contradictory combinations of conditions such as:
Here, if A is not 1, the whole LINE will not be output and that is an end to the matter: the test for A = 2 is short-circuited and the "X" will never be output.
Present/Absent When Clause: Operation
-
Report writer tests the condition operand of your PRESENT WHEN clause each time it begins the processing of the report group. If the condition is true, the field is output normally. If the condition is false, the entry is ignored. (For ABSENT WHEN , this rule applies vice versa.) If the entry is a group entry, all the entries beneath it, including all its elementary entries, are also ignored. When report writer "ignores" your entry, it treats the entry, for that instant only, as though you had not coded it. Imagine the entry drawn in a rectangle of paper and imagine that you have a blank card that you can place over the rectangle to "mask" it out:
Remember, when the PRESENT WHEN is not on an elementary entry, your masking "card" must be large enough to cover all the lower-level entries, down to elementary level, as far as the next entry at the same level or higher. Now, to find out what will be produced when an entry is ABSENT, just cover the entry with the mask, so that it disappears from view. The remaining entries are what report writer "sees" at that instant, and therefore what it will output. For example, suppose that the field CITY-FLAG is 1 and INS-FLAG is zero in the example above. What will report writer produce? Just move the mask over the INS-FLAG group entry, as shown above, and this is what results:
Keeping this simple principle in mind, consider the practical applications described in the following paragraphs.
-
To "blank out" a field with an absolute COLUMN, place your PRESENT WHEN on the absolute COLUMN entry and follow it with another absolute COLUMN entry:
If HOUSE-NO-FLAG is not 1, the entry in column 4 disappears. Because the following column is in an absolute position, the first entry is blank:
This method also enables you to blank out an absolute LINE entry from a set of absolute LINE entries, leaving a gap in the printed output.
-
To insert a conditional field into the report line so that it displaces the fields that follow, simply make the entries that follow relative:
The word DEBIT displaces the next field to the right because the next field has a relative COLUMN clause (COL +1). Place your "mask card" over the DEBIT entry and you will see what occurs when its group is not produced: the AMOUNT field is the first and only field to be produced, and its COLUMN number is +1. It therefore appears in column 1.
Similarly, the HOUSE-NUMBER field in the previous paragraph could be treated as a conditional insertion item by revising the code as follows. (The "<" symbol eliminates the gap after short HOUSE-NUMBERs.)
-
To place one of a series of alternative entries into the same column positions, code several entries, each with a PRESENT WHEN clause. Take care that the conditions are mutually-exclusive so that none of the fields can overlap:
Notice that the conditional fields need not all start in the same column and that the column numbers need not be strictly in sequence, provided that they are in sequence when we mask out the entries that are ABSENT.
If all your entries start in the same column and are all literals or identifiers with the same PICTURE, you will find it more convenient to use a multiple-choice entry. (See The Multiple-Choice Form, below.)
You can also use the technique shown here to choose one LINE from a set of alternative absolute LINE entries.
-
To string out (concatenate) a number of conditional fields along the report line, where any combination could be present, use a series of relative conditional entries:
The dummy entry specifying COL 14 gives you an anchor point at which to begin. It ensures that the first sport-field will appear in column 16.
If you include many optional fields using relative COLUMNS, you may run the risk of causing line overflow if a large number happen to be present. If you want report writer to "wrap the data round" on to a continuation line, you must code a WRAP clause (see 3.28). Otherwise, it will truncate the line and create a run time line overflow message.
A similar problem might arise if you define an entry in an absolute column following your series of optional entries. If there were too many entries present, report writer might signal a run time column overlap error. If there is a risk of line overflow or column overlap, you must do some extra processing before you GENERATE the line, to make certain that no more than the maximum number of fields will be present.
-
To print one or more of a series of conditional lines in a report group, use relative LINE clauses and code your PRESENT WHEN clauses at the LINE level or above:
In this example, the lines showing AGE OF SPOUSE and NO. OF CHILDREN are not to be produced unless there is a "family membership" condition, and the line showing GOLF SUBSCRIPTION is not to appear unless the member plays golf. Here is some suitable report writer code:
Because report writer only "sees" the lines that have not been "masked out", it performs a sophisticated page-fit test. Report writer will test the availability of only the number of lines that will actually be output. If THOMPSON in the above example begins on line 59 of a 60-line page, his record will appear on that page because at that particular instant the DETAIL group is actually only 2 lines in depth.
The form CONTROL IS control-id is a special condition that can be used only in a PRESENT WHEN clause within a multiple CONTROL FOOTING. It is true if the level of the CONTROL FOOTING currently being generated is that of control-id. For example, if the TYPE clause is:
01 TYPE CF FOR COUNTY, CITY, STREET.
You may introduce any amount of variation for each level by coding, for instance:- If PRESENT WHEN is used in the same entry as an OCCURS clause or a multiple SOURCES or VALUES, the PRESENT WHEN applies to each occurrence individually.05 PRESENT WHEN CONTROL IS CITY. 07 COL 1 "Name of city:". 07 COL +2 PIC X(20) SOURCE CITY.
Effect of Present When on Sum
The general principles of the PRESENT (or ABSENT) WHEN clause apply when you use it with a SUM clause or with an item that is totalled. Report writer acts according to certain vital principles, as follows:
-
Only those SUM operands that were PRESENT when they were processed will be added to a total field. An item will not be added if it is subject to a PRESENT WHEN and the condition is false. This means that you may total a series of "optional" fields and obtain a total that is true in the sense that only the fields that are processed appear in the total field. (The word processed includes the case of unprintable fields - those having no COLUMN clause - which do not appear in the report.)
The following example illustrates this principle:
-
If you write a SUM clause and a PRESENT WHEN together in the same entry, the total will not appear in the report if the entry is not present . But neither will it be cleared to zero, because no total is cleared until it has been output. Values will continue to be accumulated in the total field even though the SUM entry may not always be present. In other words, the PRESENT WHEN in the SUM entry can delay the generating and clearing of your total field but it has no effect on the totalling itself.
These facts may be utilized if you wish to generate a number of fields repeatedly but delay the appearance of their cross-foot total. In the following example, we have a variable number (up to 31) of fields, but only up to five will fit on a line. The total also occupies a field in the line. The following solution takes advantage of the fact that if a DEPENDING ON operand is higher than the maximum, the maximum (in this case 5) is assumed. (This problem can also be resolved now using the WRAP clause.)
-
To accumulate a series of totals split up by some category, that is into separate "pigeonholes" or "buckets", you may use a series of unprintable SUM fields partitioned by a series of mutually exclusive (and exhaustive) PRESENT WHEN condition clauses. Suppose that you wish to print "Sales of Ice Cream" and you want to total separately the sales of Vanilla, Strawberry and Chocolate flavors.
This is done by splitting up the sales entry invisibly into vanilla, strawberry and chocolate sales, as though we were actually splitting it thus at the place where it is printed. We then SUM each unprintable entry to form three separate totals:
If you have a larger, or variable, number of categories, it will be easier to defined repeating values and totals using OCCURS. Suppose that the flavors VANILLA, STRAWBERRY etc. are held in a table W-FLAVOR OCCURS 20. The following code could now replace the corresponding entries used above:
The Multiple-Choice Form
-
If you need to specify a series of alternative contents for a particular elementary field, you can do it with a single entry, instead of several separate entries containing PRESENT WHEN clauses. You code the entry with several SOURCE, VALUE, or FUNCTION clauses, each followed immediately by a PRESENT WHEN clause. One of the PRESENT WHEN clauses, and only one, may be of the form PRESENT WHEN OTHER. It is normally placed last in the list (although this is not syntactically required).
-
Report writer scans your WHEN conditions, starting with the first in the order of coding, until it finds a condition that is true. It then uses the SOURCE, VALUE, or FUNCTION clause preceding that PRESENT WHEN clause and ignores all the remaining PRESENT WHEN and SOURCE, VALUE or FUNCTION clauses. So your conditions need not be mutually exclusive: the testing is on a "first-come-first-served" basis. Here is an example:
The contents of TAX will be produced when TYP-IND is between "B" and "Z" inclusive.
-
If your conditions do not cover all the possibilities, you have three choices:
- Put WHEN OTHER instead of WHEN condition against the entry you would like to act as the catch-all, default, or wastebasket:
If SMITH has TITLE-CODE equal to 0, this will result in: DEAR SMITH.
- If you specify only VALUE literal clauses without a PICTURE clause, they may be of different sizes, as in the preceding example. The actual size of the field produced will be that of the chosen value. Since SURNAME above has a relative COLUMN, you will obtain:
-
You cannot repeat the PICTURE clause in an entry (nor any of the other clauses other than SOURCE, VALUE, and FUNCTION), so if your choices need different PICTUREs you must usually code a series of separate entries. However, you may still be able to choose a PICTURE that suits each of the choices, such as PIC ZZZ9 to cover both PIC ZZZ9 and PIC ZZ9, and thus still be able to use a single entry with a multiple-choice PRESENT WHEN clause.
-
You can form a SUM of a multiple-choice entry. Report writer will select the correct choice (if any) before adding it to the total:
This adds only the one correct choice each time.This adds only the one correct choice each time.
-
You can use the CONTROL IS control-id form of condition anywhere in a multiple-choice entry. For example:
Compatibility
Only new Report Writer provides the PRESENT / ABSENT WHEN clause.