Conditions

Conditions. 1

Types of Conditions. 1

Simple Conditions. 1

Comparison operators and Values. 1

BOOLEAN Fields, and Fields with CODES or CONDITIONS Properties. 1

BOOLEAN fields. 1

CODES.. 1

CONDITIONS.. 1

Special values. 1

$Null 1

File.$EndFile. 1

File.$Found. 1

File.$UpdatePending. 1

File.$FreeKey. 1

$CMerge, $CMergeOut 1

DUPLICATE conditions. 1

What does DUPLICATE test?. 1

Where is DUPLICATE tested?. 1

Compound Conditions. 1

WHERE Conditions. 1

 

Conditions are widely used in Jazz;  the IF statement, WHERE and UNTIL options of FOR and I/O statements (GET, PROCESS , UPDATE, DELETE) all use the same basic rules for conditions. Conditions in Jazz are similar to those in most programming languages but the way you write the conditions, and the scope of the THEN and ELSE, are more flexible and powerful than you might be used to.

Types of Conditions

It is helpful to distinguish several kinds of condition

·         Simple Conditions.

·         DUPLICATE conditions

·         Compound Conditions

·         WHERE conditions

Simple Conditions.

Conditions are written

            Reference  Comparison-operator Value

For example: -

IF R1.Balance > 1000 THEN

    ….

IF R1.Name = LastRecord.Name THEN

    ….

 

“Reference” must refer to a single field if R1 has TYPE SQL, but for other types it may refer to a single field or a GROUP.  If it is a GROUP then comparison treats the group as a CHAR field of appropriate length.  “Reference” may not be a generic reference.

 

Value can be another field, a constant, or a numeric expression.  If “field” is a group the value is treated as a CHAR field of appropriate length.  

 

When you compare a reference and a constant, the reference must come first.  For example you cannot write

            IF 1000 < Record1.Balance THEN

 

If the field has BOOLEAN type then you may omit the rest of the comparison.  Jazz treats

DEFINE R1 DATA(

    Flag BOOLEAN);

IF R1.Flag THEN;

as equivalent to

IF R1.Flag = true THEN;

Comparison operators and Values

Comparison operators are: -

Operator

Meaning

=

Equal to

<> 

Not equal to

> 

Greater than

>=

Greater than or equal to

< 

Less than

<=

Less than or equal to

IN

In a list of values

BETWEEN

Between two values

~ or LIKE

Pattern match

DUPLICATE

Compare with previous value

 

IN, BETWEEN, and LIKE follow SQL rules.  LIKE, IN and BETWEEN can be written in normal IF and FOR statements, not just in an SQL GET or PROCESS statement’s WHERE condition, but LIKE is not valid in a non-SQL FOR  UNTIL condition.  The syntax of these options: -

IF EMPLOYEE.MIDINIT IN ('A', 'C', 'H'); Note the parentheses.

IF EMPLOYEE.SALARY BETWEEN 10000 & 20000;

You probably wrote & as AND.   The lower value must be given first:  EMPLOYEE.SALARY BETWEEN 20000 & 10000 is always false.

IF EMPLOYEE.NAME LIKE 'Bar%'

 

Operators and values must be compatible with the field being tested.  For example, if the field is numeric then the value must also be numeric. If the field is a group then the value is treated as a CHAR field of appropriate length, and may be a string constant like 'Abcdefg', another group, or a CHAR or VARCHAR field.   Arithmetic (numeric) expressions are allowed: for example you can write

          IF JZ.IX1 > JZ.IX2 * 2 THEN;

but string expressions are not: it is not permitted to write  IF R.Name = JR.Name1 && R.Name2  THEN;

See DUPLICATE conditions below for information about the DUPLICATE operator.

BOOLEAN Fields, and Fields with CODES or CONDITIONS Properties.

Fields defined as type BOOLEAN or with CODES or CONDITIONS properties get special handling, particularly in conditions.  You can only test these fields for their special values, and you may only use comparison operators = or <>.  Other operators like > imply an order, but coded values don’t have an order: you can’t say that “true is greater than false”.  Such a statement is simply meaningless.

BOOLEAN fields

A BOOLEAN field is a field that can have only two values, true or false.  There are three different formats of BOOLEAN fields, CHAR(1), TINYINT, and SMALLINT, but whichever format you use you will always test the values for the special values true or false, never for the code representation.  For example: -

DEFINE W DATA(

    Bool1 BOOLEAN,

    Bool2 CHAR(1) BOOLEAN,

    Bool3 TINYINT BOOLEAN,

    Bool4 SMALLINT BOOLEAN,

    X SMALLINT);   

IF W.Bool2 = true THEN;

    W.X = 1;

END IF;

You may know that CHAR(1) BOOLEAN fields store true as 'Y', but writing a test for 'Y' will result in error messages

IF W.Bool2 = 'Y' then;

    #065 S Code or condition value required here

    #029 E ''Y'' is invalid here

 

If the field is BOOLEAN then the condition may simply name the field, implying a test for true.  For example: -

IF W.Bool2 THEN;

is equivalent to the earlier condition

IF W.Bool2 = true THEN;

 

Tests for false are actually tests for “Not true”.  Thus a condition

IF W.Bool2 = false THEN;

is true if W.Bool2 has anything other than the true value, which for this format is 'Y'. The value does not have to be 'N' for the condition to be true, and the following condition is identical to the one above: -

IF W.Bool2 <> true THEN;

CODES

As with BOOLEAN, for a field defined with CODES the condition will refer to the field’s value, not its code.  For example, if State is defined: -

State CHAR(3) CODES(NSW:'New South Wales',VIC:Victoria,TAS:Tasmania,QLD:Queensland),

then you’d test

IF W.State = Victoria THEN;

not

IF W.State = Vic THEN;

    #065 S Code or condition value required here

    #029 E 'Vic' is invalid here

As with BOOLEAN, the only valid operators are = and <>.

CONDITIONS

If a field’s definition includes a CONDITIONS property then there is a predefined condition that can easily be tested for = or <>.  For example a record CondTs2 contains

    DECLINE-REASON PIC '9(03)' CONDITIONS(284 TO 295:IBS-VALID-DECL-REASON),

This allows us to write

IF CondTs2.DECLINE-REASON = IBS-VALID-DECL-REASON THEN;

to test whether the value of the PIC '9(03)' field is in the range 284 to 295 (inclusive).

 

CONDITIONS properties can be simple

AFF2 CHAR(4) CONDITIONS('M1 D':MC-STD-CR, …

or give lists of values

AFF2 CHAR(4) CONDITIONS(,'E11M','E12M','E13M','E14M','E15M','E16M','E17M':VALID-AFF, ),

as well as ranges as above.

 

COBOL programmers will recognise CONDITIONS as “Level 88 definitions”.  Note the different syntax: in Jazz write the reference to a condition as a normal condition expressed with the = or <> operator: -

IF CondTs2.AFF2 = VALID-AFF THEN;

You do not simply name the condition as you would in COBOL: -

IF VALID-AFF THEN;  <=  THIS IS NOT VALID

Special values

$Null

If the value is $Null then the field must have property OPTIONAL, and the comparison can only be = or <>. 

File.$EndFile

Type BOOLEAN. Refer to File.$EndFile, e.g. IN1.$EndFile to test if the file has reached the end. 

File.$Found

Type BOOLEAN. A GET statement looks up a record using its WHERE or KEY condition.  If there is no such record the record area is initialized so that a record always exists.  File.$Found is set True if the GET found a record, False if an initialized record is created.

File.$UpdatePending

Type BOOLEAN. Set True if a record is read by GET UPDATE or PROCESS UPDATE.  If True, the record will be updated at the related END GET/PROCESS.  Pending updates can be discarded with File.$UpdatePending = False;

File.$FreeKey

Type ? (depends on the file definition) .Used with VSAM and SQL to calculate the next available key to use when creating a new record.

$CMerge, $CMergeOut

Type SMALLINT. Special value $CMerge is used to compare merge file keys.  With

PROCESS F1 MERGE F2 SKEYS (F1.KEY1, F1.KEY2, F2.KEY1, F2.KEY2) COPY F1OUT;

$CMerge = 0 if the two files match, $CMerge > 0 if F1 > F2, and < 0 if F2 > F1.  

More precisely,

IF F1.KEY1 > F2.KEY1 THEN $CMerge = 1

ELSEIF F1.KEY1 < F2.KEY1 THEN $CMerge = -1

ELSEIF F1.KEY2 > F2.KEY2 THEN $CMerge = 2

ELSEIF F1.KEY2 < F2.KEY2 THEN $CMerge = -2

ELSE $CMerge = 0

$CMergeOut behaves like $CMerge, except that instead of comparing F1 against F2, it compares F1OUT.  Thus $CMergeOut > 0 if F1OUT > F2, and < 0 if F2 > F1OUT.

These functions are useful when the logic of a PROCESS MERGE depends on knowing situations such as “Is this a new output record?”  For example, this logic will update matching records, but not produce new records from an unmatched transaction: -

PROCESS FILE1 MERGE FILE2 ON FILE1.KEY1A=FILE2.KEY1B COPY FILEOUT COUNT JZ.IX1;

    IF JZ.$CMergeOut = 0;  

        FILEOUT.BALANCE += FIle2.Payment;

        IF JZ.$CMerge > 0;

            JZ.COPY-WANTED = false;

        END IF;

    END IF;

    PRINT (JZ.IX1, FILE1.*, FILE2.*, FILEOUT.*) ;

END PROCESS MERGE COPY FILEOUT;

Refer to https://www.jazzsoftware.co.nz/Docs/JazzUGmerge.htm for more information about MERGE logic.

DUPLICATE conditions

DUPLICATE conditions compare a record or field with the previous value.  For example, you might write

PROCESS OLDMSTR MERGE Trans

        SKEYS (OLDMSTR.O-KEY,OLDMSTR.O-KEY2,TRANS.T-KEY,TRANS.T-KEY2)

        COPY NewMstr  SID(20);

    IF DUPLICATE OLDMSTR;

        #730 W DUPLICATE tests O-KEY,O-KEY2,

        JZ2.FLAG1 = True;

    ELSE;

        JZ2.FLAG1 = False;

    END IF;

    DISPLAY('Duplicate(OLDMSTR=' JZ2.FLAG1);

END PROCESS MERGE COPY NewMstr;

A DUPLICATE test names a record, a field, or a group.  In the example above, OLDMSTR is one of the input files read by PROCESS OLDMSTR …   Here’s another example, this time DUPLICATE tests a field from an array: -

FOR TABL.O-KEY(JZ2.IX);

    IF DUPLICATE Tabl.O-KEY(IX);

        JZ2.FLAG1 = True;

    ELSE;

        JZ2.FLAG1 = False;

    END IF;

    DISPLAY(JZ2.IX, JZ2.FLAG1);

*#Copy Process logic here ==>

END FOR;

What does DUPLICATE test?

If the test names a Record or Group, then DUPLICATE will test the relevant SKEY, TKEY, or KEY fields.   Key properties may be derived from the SKEYS or ON option of the PROCESS statement, as in the examples above, or from properties given in the relevant DEFINE statement. If no key properties are found, then the whole record is tested.   Message #730 will tell you what is being tested.

If the test names a single field, as in DUPLICATE Tabl.O-KEY(IX) then the field is tested and message #730 is not produced.

 

Save variables are generated into the COBOL program to hold the values of the previous record.  For example, from

PROCESS OLDMSTR MERGE Trans

        SKEYS (OLDMSTR.O-KEY,OLDMSTR.O-KEY2,TRANS.T-KEY,TRANS.T-KEY2)

        COPY NewMstr  SID(20);

    IF DUPLICATE OLDMSTR;

        #730 W DUPLICATE tests O-KEY,O-KEY2,

the generated COBOL contains

001480      03 JZ-22-DUP PIC X VALUE SPACES.                            DupTst

001490      03 JZ-22-DUP-SAVE PIC 99 VALUE ZERO.                        DupTst

001500      03 JZ-22-DUP-SAVE1 PIC XXXXX VALUE SPACES.                  DupTst

The format of these variables is the same as the corresponding key fields, OLDMSTR.O-KEY and OLDMSTR.O-KEY2.  If no key fields have been detected, then there will be a single save field with format PIC X(nn)  where nn is the record length. 

 

The field JZ-22-DUP is a COBOL BOOLEAN field which would normally hold 'Y' or 'N', but has been initialized to SPACES.   This fact is used in the generated COBOL logic, which always returns False from the first test.  This guards against the possibility that the very first record might have the initialization values.

Where is DUPLICATE tested?

DUPLICATE tests for duplication at the point in the program where it is written, not at the beginning of the loop, which may be directly within the PROCESS loop, or within a ROUTINE invoked by PERFORM.   Each DUPLICATE test is unique, and will have its own set of save variables and result flag, so if you repeat a DUPLICATE test the results will be recalculated and will reflect changes in the object tested.  It is recommended that if you need to know the results of the test in more than one place, you should save the result, either with IF logic as above or else a direct assignment: -

    JZ2.FLAG1 = DUPLICATE Tabl.O-KEY(IX);

Compound Conditions

You can combine several conditions using & (meaning AND) and | (meaning OR). & and | are called “Boolean Operators”. For example: -

IF R1.X >  R1.Y & R1.Flag THEN;

Here we have combined a simple comparison of two numbers with a test of a BOOLEAN field, using an implied = true.  In the absence of parentheses conditions are evaluated left to right.  Parentheses are particularly vital when you are using | (OR).  For example the two tests

IF R1.X >  R1.Y & R1.Flag | R1.Flag2 THEN;

IF R1.X >  R1.Y & (R1.Flag | R1.Flag2) THEN;

give different results.

 

You will probably write these conditions using AND and OR.  Jazz will recognize the use of these words in this context and replace them with the formal operators & |.

DUPLICATE conditions cannot be part of a Compound Condition.

WHERE Conditions

WHERE conditions are written just like conditions in IF statements, but in some circumstances they may behave slightly differently as the way that a WHERE works depends on the file type from which records are being read.

 

Case #1:  filtering a sequential file.  In a BATCH program you can read a physical-sequential file (type F, FB, etc).  Every record is read into your program, but you can use WHERE to discard the records that you don’t want: -

            PROCESS File WHERE (File.Balance > 1000);

                ….

            END PROCESS File;

Here the WHERE clause is exactly like an IF, and this logic is equivalent to

            PROCESS File;

                IF File.Balance > 1000 THEN;

                    ….

                END IF;

            END PROCESS File;

 

Case #2.  Reading VSAM with PROCESS or GET. As with a sequential file you can write PROCESS file WHERE(condition);, but unlike a sequential file you can write such statements within a loop (perhaps an outer PROCESS), and within CICS programs.  Here the WHERE is not simply a filter: it specifies that particular records are read using a “Browse”, and the fields named must have been defined with a key property (KEY, DKEY, or UKEY), or be within a key GROUP.  Comparison operators must be = or >=: the PROCESS will attempt a keyed read and then return all the records meeting the criteria.  With GET, if there are many records that meet the criteria the first will be returned in a batch program, but several may be returned with a paging process with classical CICS and web services.

 

Case #3.  Reading SQL with PROCESS or GET.  Within Jazz PROCESS File WHERE(condition) is the same whether File is a VSAM record set or a table in an SQL database.  In COBOL however the implementation is very different:  in the case of VSAM records are read and considered by your program whereas for SQL your program uses a SELECT statement that instructs the database which records it wants, and the unwanted records are never seen.  You may not know which fields within the database are keys, and only your program’s performance will tell you whether you are scanning the whole database to find the record that you want or going straight to them with keyed retrieval. 

 

Null values (in Jazz, $Null) are handled differently in SQL. To SQL a NULL field does not have a value at all, so its value can never be equal to, or greater than or less than, any other value.  Even another NULL value!  So that

SQLT2.Charfield = $Null;

PROCESS SQLTab WHERE (SQLTab.charfield = SQLT2.charfield) …

returns NO RECORDS.  It DOES NOT return all the records from SQLTab with NULL values.  If you want these records then you write

PROCESS SQLTab WHERE (SQLTab.charfield = $NULL) …