The Assignment Statement

The Assignment Statement 1

Format 1

Statement Options – TRIM, EXCEPT. 2

Expressions. 2

Numeric expressions. 2

String Expressions. 3

TRIM, RTRIM, LTRIM.. 3

Assignments with += etc. 4

Functions and Special Values. 4

Generic Assignments. 5

EXCEPT. 6

Redefinitions and Generic Assignment 6

Tables and Subscripted References. 7

 

Assignment statements compute and copy data from field to field within your program. They may be simple assignments: -

Record1.Customer-Name = 'Robert';

They may involve calculations

LineItem.Extended-Value = Part.UnitCost * LineItem.Quantity;

Generic assignments may assign many fields at once

OutputRecord.* = InputRecord.* ;

Format 

Assignment statements have this general format: -

target [, target]... = expression [Option];

 

The assignment symbol is normally “=”, but may instead be “+=”, “-=”, “*=”, or “/=”.  See notes below.

 

They follow these general rules

1.    Referenced fields and records must have already been defined within the program.

2.    Multiple targets are only valid for simple assignments.

a.    You may not specify more than one generic target, i.e.

            Record1.*, Record2,* = Record3.*

is not valid

b.    You may not specify multiple targets if you are using a string expression.  Thus

String1, String2 = Field1 && Field2

is not valid.

c.     All targets must have the same general type. For example, you cannot mix numeric, string, and date fields.

3.    The target(s) must be compatible with the expression. Thus if the expression is a string, the target cannot be a numeric field

4.    If the target is a generic reference, then the expression must be a single generic reference.  For example

OutputRecord.* = InputRecord.*

See Generic Assignments below for more information.

Statement Options – TRIM, EXCEPT

RTRIM, LTRIM, and TRIM.  These are only valid for String expressions, or for assignments of single CHAR fields to VARCHAR - see below.

 

EXCEPT, STRICT, SIMPLE.  These are only valid for Generic Assignments – see below.

 

NOTNULL.  This is only valid when the target of the assignment is an OPTIONAL field in a SQL record.  See SQL and OPTIONAL Fields for more information.

Expressions

If the target is a field (or several fields), then the expression can be

·         a constant

Record1.Customer-Name = 'Robert';

Record1.MinimumPayment = 100.00;

·         a reference to another field

Record1.Customer-Name = InScreen.Customer-Name

·         an expression in which a value is calculated

Record1.MinimumPayment = Parameter.PaymentClass * 100;

Record1.Customer-Name = Input.FamilyName && ', ' && Input.GivenName;

There are several types of expressions.  The expression type is determined from the target variable: if the target is numeric then the expression must be numeric, and so on.

Numeric expressions. 

These have a numeric value. An example is

Parameter.PaymentClass * 100

Numeric expressions may include

·         Numbers (numeric constants)

·         Numeric fields – fields with type DECIMAL, MONEY, BIGINT, INTEGER, SMALLINT, FLOAT, LONG

·         Arithmetic operators + (Plus), - (Minus), * (Multiply), / (Divide), and ** (to the power of)

·         Parentheses, i.e. brackets, to group operands and operators

Arithmetic expressions are evaluated according to the normal rules of Mathematics, meaning that the expression is evaluated left to right except that anything within (…) is evaluated first, and Multiplication and Division is done before Addition and subtraction.

 

Here are some examples. With B = 2, C = 3, D = 4, and E = 5,

A = B + C * D

A is set to 14: C * D is evaluated first giving 12, this is added to 2. 

If we wanted B and C to be added first we’d put them in brackets: this sets A to 20: -

A = (B + C) * D

It doesn’t hurt to add brackets when they’re unnecessary. For example, A = B + (C * D) is equivalent to A = B + C * D, but it may be clearer to a human reader. 

 

While you can make arithmetic expressions as complicated as you like, several simpler expressions may be easier to understand, both for you and other human readers, and for Jazz software. 

String Expressions

Strings are sequences of characters, so string expressions are expressions which return this type of value.  They basic form is a simple assignment of a string constant or a CHAR or VARCHAR field: -

Record1.Customer-Name = 'John'

Record1.Customer-Name = InScreen.Customer-Name

 

If the assignment target is longer than the string value, then the value is extended with blanks. For example, if Record1.Customer-Name had been defined as CHAR(30), then

Record1.Customer-Name = 'John'

would assign 'Johnbbbbbbbbbbbbbbbbbbbbbbbbbbb' to it. Here “b” represents a blank.

 

If the expression value is longer than the target string, the value is truncated.  Thus if Record1.Customer-Name had been defined as CHAR(3), then

Record1.Customer-Name = 'John'

would have assigned value 'Joh'.

Substring References

As with COBOL’s “Address modification”, you can give starting position and length to specify a substring.  Thus with definition: -

DEFINE W DATA(

    Name CHAR(26) VALUE 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',

    VName VARCHAR(30) VALUE 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',

    Char2 CHAR(2),

   

W.Char2 = W.Name(3:2);

#539 W Char2 is shorter than source: value may be truncated

assigns value 'CD' to W.Char2.  Message #539 will be produced if W.Char2 is shorter than W.Name, without taking account of the length value.

 

The rules for a substring references are: -

1.            They can only appear in the source (right-hand side) of assignment statements.

2.            The source variable, for example W.Name, must have type CHAR or VARCHAR.  You cannot use this with a GROUP, a generic reference, or any other type of field.

3.            If the source variable has dimension then you must give subscripts before the substring reference.  Thus if W.Name had been defined 

                        Name (5) CHAR(26) VALUE 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',

then you’d write a reference such as

            W.Char2 = W.Name(3)(5:2);

to assign characters 5 and 6 of the 3rd occurrence of W.Name.  A subscript is required when there is a dimension, but a subscript reference, if allowed, is always optional.

4.            A substring reference has form ( Start : Length ).   Start and Length may be numbers, or scalar (= without dimension) SMALLINT fields.  Start must have value 1 to the length of the source field, and length may have value 0 to the remaining length of the source field.  Thus

            W.Char2 = W.Name(26:2);

is invalid because the value would extend beyond the length of W.Name.  When Start and Length are both numbers, as here, then Jazz will check their validity when [Check] is clicked, but if either is a SMALLINT field then the generated COBOL will contain statements to ensure their validity at run time.  There are no run-time messages, but values are coerced into the valid range: -

            W.Name(W.Start:*) will use value 1 as starting position if W.Start is smaller than 1, and 26 if it is larger than 26 (the length of W.Name).

            W.Name(W.Start: W.Length) will use length value 0 if W.Length is negative or the available length of W.Name if it is too large.

If a variable Start is given with a fixed length, then the length assigned will be reduced if necessary.  Thus

W.Start = 23;

W.Char10 = W.Name(W.Start:10);

will assign 'WXYZ' to W.Char10, not 'WXYZabcdef' where 'abcdef' represents the 6 bytes of data that happen to follow W.Name. This is different behaviour to COBOL. If W.Char10 has type VARCHAR then its length will be set to 4, not to 10.   

5.            Write Length as * to mean “To the end of the string”.   Thus write
            W.VName = W.Name(3:*);
to set
W.VName to 'CDEFGHIJKLMNOPQRSTUVWXYZ'
.   Note the difference to COBOL, where you would have written W.Name(3:) If you omit the * then Jazz will insert it, with a warning message.

6.            Assignment to a VARCHAR field will set the target length from the substring reference.   Thus

            W.VName = W.Name(3:2);

will set the value of W.VName to 'CD' and its length to 2.  

            W.VName = W.Name(3:*);
sets the length of
W.VName to 24.

As normal, if the length is too great, the length is set to the maximum length possible (30 in this case) and the value is truncated.   If the source fields is also VARCHAR, then the maximum length possible is the current length: for example if VName is set to 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' giving it a current length=26, then a substring reference will be terminated at position 26. 

Concatenation

The only operator permitted in a string expression is “&&”, meaning “Concatenate”. This joins the two (or more) string elements together.  Each element can be a CHAR or VARCHAR field, or a string constant: -

DEFINE Record1 DATA(

        FamilyName VARCHAR(30),

        GivenName VARCHAR(30));

DEFINE Record2 DATA(

        NAME VARCHAR(62));

Record1.FamilyName = 'Barnes';

Record1.GivenName = 'Robert';

Record2.Name = Record1.FamilyName && ', ' && Record1.GivenName;

This assigns 'Barnes, Robert' to Record2.Name.  Concatenation expressions are interpreted left-to-right, and should not contain brackets or other punctuation.

 

Note the constant, ', ', separating the two fields. Without this we’d get a result like 'BarnesRobert'.

 

Note also the use of VARCHAR: if FamilyName and GivenName had been defined CHAR then the value would have included 24 blanks after “Barnes”. Compare the results above with

DEFINE Record1 DATA(

        FamilyName CHAR(30),

        GivenName CHAR(30));

DEFINE Record2 DATA(

        NAME VARCHAR(62));

Record1.FamilyName = 'Barnes';

Record1.GivenName = 'Robert';

Record2.Name = Record1.FamilyName && ', ' && Record1.GivenName;

Here Record2.Name is set to 'Barnes                        , Robert                         '.

To achieve the same result with CHAR as with VARCHAR, use RTRIM (see below), e.g.

Record2.Name = Record1.FamilyName && ', ' && Record1.GivenName RTRIM;

TRIM, RTRIM, LTRIM

DEFINE R DATA(

        F1 CHAR(10) VALUE '  CDE JH  ',

        F2 VARCHAR(10));

 

TRIM removes (trims) leading and trailing blanks, so that

R.F2 = R.F1 TRIM;

sets F2 to 'CDE JH' (length = 6).  Note that the blank between E and J is retained.

 

RTRIM removes trailing (right-hand) blanks: -

R.F2 = R.F1 RTRIM;

sets F2 to '  CDE JH' (length = 8). 

 

LTRIM removes leading (left-hand) blanks: -

R.F2 = R.F1 LTRIM;

sets F2 to 'CDE JH  ' (length = 8). 

 

TRIM, RTRIM and LTRIM affect only values with type CHAR or VARCHAR, and fields from 3270 screens, and cannot be used with constants or fields with any other type.  Thus you could write

Record2.Name = Record1.FamilyName && ',       ' && Record1.GivenName RTRIM;

and have several blanks inserted between FamilyName and GivenName.  Similarly, RTRIM is usually unnecessary for VARCHAR fields and fields from 3270 screens, as these have built-in length fields.   Trim options TRIM, RTRIM and LTRIM may not be used if there is a substring reference.

TRIM Special Values

If the source field (e.g. R.F1 above) has value ‘NULL’, ‘VALUE’, or ‘SPACE’ then the value assigned is: -
            NULL.  The value is a zero-length character string, and (if the field is defined in a SQL table and is nullable, i.e. it is not defined as REQUIRED) the indicator field will be set to -1 (field absent).

            VALUE.  The value is defined with its explicit or implicit VALUE property.  This is usually the same as NULL.

            SPACE.  These is equivalent to assignments of SPACE.  It does not set nullable SQL fields to NULL.

These special values must be written in upper case:  if R.F1 = ‘Null’ then this is treated like any other four characters.

Implied TRIM functions

An ACCEPT statement will trim input data before testing them for validity, so you should be aware that the special values NULL, VALUE, and SPACE will be handled as above.

Assignments with += etc

The target variable can appear in the source expression. For example, incrementing a loop variable is simply achieved with

LoopCount = LoopCount + 1

The assignment symbols +=, -=, *=, and /= are convenient shorthand for this kind of assignment. Thus

LoopCount += 1

is equivalent to the earlier assignment. +=, -=, *=, /= are valid for numeric assignments.

 

For String assignments you can use &=. For example

JZTMVS.Msg &=  'Min>59;' RTRIM;

is equivalent to

JZTMVS.Msg =  JZTMVS.Msg && 'Min>59;' RTRIM;

Functions and Special Values

You can refer to any COBOL special values, for example Spaces and Zero, and COBOL Intrinsic Functions: -

w.name1 = spaces;

You can refer to Jazz built-in Functions, which will be named starting with $.   There are also some Jazz special names that you can refer to, such as JZ.JZReturnCode, that have meaning in particular contexts.

 

For a list of these functions and names, refer to JazzLRMBuiltInFunctions

Generic Assignments

A generic assignment assigns all the fields of one record or group to the like-named fields in another (except for FILLER).  For example, suppose that we had defined INPUT1 and RECORD1 like this:-

DEFINE INPUT1 DATA(

        NAME CHAR(30),

        ADDRESS CHAR(30),

        CITY CHAR(15),

        BALANCE MONEY(7,2));

DEFINE RECORD1 DATA(

        CODE CHAR(1),

        NAME CHAR(30),

        BALANCE MONEY(7,2)); 

 

Now if we write

RECORD1.* = INPUT1.*;

this is equivalent to the simple assignment statements:

RECORD1.NAME = INPUT1.NAME;

RECORD1.BALANCE = INPUT1.BALANCE;

Fields CITY, ADDRESS, and CODE are ignored.

 

The source of a generic assignment must be another generic expression or the Jazz function $Init (which Jazz will qualify to JAZZ.$Init):-

T.* = JAZZ.$Init;

This is identical in effect to the assignment statement

T = JAZZ.$Init;

 

It is NOT valid to assign a single field or constant to a generic expression: -

T.* = SPACES;

#543 S Source SPACES is invalid for a generic assignment. Reason: Constant

 

STRICT and SIMPLE generic assignments

Generic assignments like

RECORD1.* = INPUT1.*;

apply STRICT rules to determine which fields are included in the assignment.   Since you didn’t write the STRICT option, message 698 (information-level only) is produced.

 

With STRICT rules, to be included in a generic assignment the fields must have the same names, including the names of containing groups. For example, record In1A is defined like this: -

DEFINE IN1A TYPE(FB) DATA(

    Region PIC '99',

    Filler CHAR(3),

    District PIC '99',

    Filler CHAR(4),

    Name CHAR(15),       

    Filler CHAR(2),    

    SalesThisMonth PIC '99999.99',

    Filler CHAR(3),   

    SalesYTD PIC '99999.99',   

    Filler CHAR(4),     

    Cardholder CHAR(1),   

    Filler CHAR(4),      

    DateCommenced CHAR(10),

    Filler CHAR(14))

    DSNAME '@Project.@Group.SRCLIB(DTDTA1)';

and record IN1 is defined like this: -

DEFINE IN1 TYPE(VB) DATA(

    JZ-Key GROUP KEY,

        Region DECIMAL(3),

        District DECIMAL(3),

        END GROUP,

    Name CHAR(15),

    SalesThisMonth DECIMAL(7,2),

    SalesYTD DECIMAL(7,2),

    Cardholder CHAR(1),

    DateCommenced CHAR(10))

    DSNAME('IBMUser.Files.IN1');

 

Because Region and District are within group JZ-Key in IN1 they are not included in the generic assignment, they have to be individually assigned in this program.  The Jazz message is helpful in alerting us to this potential issue: -

COPY in1a;

COPY IN1;

PROCESS in1A;

    PRINT (IN1A.*); 

    In1.* = IN1a.*;

    #207 I Name,SalesThisMonth,SalesYTD,Cardholder,DateCommenced included in generic assignment

    In1.Region = in1a.region;

    in1.district = in1a.district;

    WRITE in1;

END PROCESS in1A;

 

With SIMPLE the group structure is ignored, and it is sufficient for the field name to be found.  You would use this in the case above to avoid the need for the individual assignments

    In1.Region = in1a.region;

    in1.district = in1a.district;

Be careful if there is ambiguity, as in

DEFINE IN1 TYPE(VB) DATA(

    JZ-Key GROUP KEY,

        Region DECIMAL(3),

        District DECIMAL(3),

        END GROUP,

    OLD-Key GROUP,

        Region DECIMAL(3),

        District DECIMAL(3),

        END GROUP,

   

With SIMPLE you can only refer to the first occurrence of the name, and the duplicate names in OLD-Key will be ignored.

EXCEPT

Use EXCEPT to exclude fields from a generic assignment.  For example

IN1.* = In1a.* EXCEPT(IN1.Region, IN1A.RDKey.District);

omits the fields Region and District from the generic assignment.  Note that you can name fields on either side of the assignment.  However if you name an unrelated field then there is no message and the irrelevant item is ignored.  Thus in the program above if you add this option to the original statement

IN1.* = In1a.* except region, district;

and then click [Check] it becomes

IN1.* = In1a.* EXCEPT(Types.Region, IN1A.RDKey.District);

#207 I RDKey.Region,Name,SalesThisMonth,SalesYTD,DateCommenced, included in generic assignment

As you see there is no message about the omission of Types.Region, and RDKey.Region from the assignment.

Redefinitions and Generic Assignment 

When redefined fields occur within a generic reference, as in: -

DEFINE RECORD1 DATA(

    ACCOUNT NUMERIC(8),

     BANK NUMERIC(2) REDEFINES RECORD1.ACCOUNT,

     …);

DEFINE RECORD2 DATA(

    ACCOUNT NUMERIC(8),

     BANK NUMERIC(2) REDEFINES RECORD1.ACCOUNT,

     …);

then both ACCOUNT and BANK will be assigned by

RECORD1.* = RECORD2.*;

even though assignment of BANK is superfluous.

 

Fields are assigned in order of their definition position within the target record.

Tables and Subscripted References

If a field is defined as a table, i.e. with one or more dimensions, then you must refer to it with the correct number of subscripts. For example,

DEFINE D DATA(

        A SMALLINT,

        B (3) SMALLINT,

        C (3) SMALLINT,

        D(3) INTEGER,

        E (2, 3, 4) SMALLINT,

        Gr1 (2) GROUP,

                F (3, 4) SMALLINT,

                END GROUP);

Just as we can set the value of A to 1234: -

            D.A = 1234;

we can refer to elements of a table by specifying a subscript: -

            D.B(2) = 5678;

            D.A =  D.B(2);

We must give the correct number of subscripts, and so we are not permitted to write

            D.B = D.C;

to assign the whole array. Instead we use “(*)” to indicate “All of this dimension”, writing

            D.B(*) = D.C(*);  which Jazz will change to D.B(*) = D.C($IX1);

This is only valid if the arrays have exactly the same dimension, as they do here, and imply a loop like

FOR D.B(IX);

    D.B(IX) = D.C(IX);

END FOR;      

Because there is an implied loop, a statement like D.B(*) = D.C($IX1); is valid as long as an assignment from an element of D.C to an element of D.B is valid. Thus we could write

            D.D(*) = D.B($IX1);

and each SMALLINT value becomes an INTEGER value.  Similarly, we can write

            D.B(*) = D.E(1, $IX1, 1);

(here we must write $IX1 explicitly because it is not in the same position as the * in the target).

 

We can also write statements like this when the dimension of the source and target are different. Thus

DEFINE D DATA(

        B (3) SMALLINT,,

        E (2, 5, 4) SMALLINT,

           

D.B(*) = D.E(1, $IX1, 1);

the first three elements of E are assigned, ignoring elements 4 and 5. However if the dimension of E is less than the corresponding dimension of B, this is not valid.

Date Expressions

The rules of DATE assignment and arithmetic are detailed in this Users’ Guide page JazzUGDate.htm