tags:

views:

841

answers:

2

I'm having the following problem in a COBOL program running on OpenVMS.

I have the following variable declaration:

       01 STRUCT-1.
           02 FIELD-A       PIC S9(6) COMP-3.
           02 FIELD-B       PIC S9(8) COMP-3.

       01 STRUCT-2.
           03 SUB-STRUCT-1.
               05 FIELD-A   PIC 9(2).
               05 FIELD-B   PIC 9(4).
           03 SUB-STRUCT-2.
               05 FIELD-A   PIC 9(4).
               05 FIELD-B   PIC 9(2).
               05 FIELD-C   PIC 9(2).

And the following code:

      * 1st Test:     
           MOVE 112011   TO FIELD-A OF STRUCT-1
           MOVE 20100113 TO FIELD-B OF STRUCT-1

           DISPLAY "FIELD-A       : " FIELD-A OF STRUCT-1 CONVERSION
           DISPLAY "FIELD-B       : " FIELD-B OF STRUCT-1 CONVERSION

      * 2nd Test:
           MOVE 112011   TO SUB-STRUCT-1.
           MOVE 20100113 TO SUB-STRUCT-2.
           MOVE SUB-STRUCT-1 TO FIELD-A OF STRUCT-1
           MOVE SUB-STRUCT-2 TO FIELD-B OF STRUCT-1

           DISPLAY "SUB-STRUCT-1  : " SUB-STRUCT-1
           DISPLAY "SUB-STRUCT-2  : " SUB-STRUCT-2
           DISPLAY "FIELD-A       : " FIELD-A OF STRUCT-1 CONVERSION
           DISPLAY "FIELD-B       : " FIELD-B OF STRUCT-1 CONVERSION

Which outputs:

FIELD-A       :  112011
FIELD-B       :  20100113
SUB-STRUCT-1  : 112011
SUB-STRUCT-2  : 20100113
FIELD-A       :  131323
FIELD-B       :  23031303

Why FIELD-A and FIELD-B hold values different from what I move into them in the second test?

I've other moves from DISPLAY to COMP-3 variables in my program where I don't get this behavior.

+2  A: 

In COBOL, Group level data are typeless and are moved without casting.

Element level data always have an associated data type. Typed data are cast to match the type of the receiving element during a MOVE.

In the first instance you MOVE a literal numeric value (112011) to a packed decimal field and the compiler converts it to the correct data type in the process. Just as you would expect in any programming language.

In the second instance you MOVE a literal value to a group item. Since this is a group item the compiler cannot 'know' the intended data type so it always does group moves as character data (no numeric conversions). This is fine when the receiving item has a PICTURE clause that is compatible with character data - which FIELD-A and FIELD-B of SUB-STRUCT-1 are. There is no difference in the internal representation of a 9 when stored as PIC X and when stored as PIC 9. Both are assumed USAGE DISPLAY.

Now when you do a group level move from SUB-STRUCT-1 to a COMP-3 (Packed Decimal) you effectively tell the compiler not to convert from DISPLAY to COMP-3 format. And that is what you get.

Try the following modifications to your code. Using REDEFINES creates a numeric elementary item for the move. COBOL will do the appropriate data conversions when moving elementary data.


       01 STRUCT-2.                  
           03 SUB-STRUCT-1.          
               05 FIELD-A   PIC 9(2).
               05 FIELD-B   PIC 9(4).
           03 SUB-STRUCT-1N REDEFINES
              SUB-STRUCT-1  PIC 9(6).
           03 SUB-STRUCT-2.          
               05 FIELD-A   PIC 9(4).
               05 FIELD-B   PIC 9(2).
               05 FIELD-C   PIC 9(2).
           03 SUB-STRUCT-2N REDEFINES
               SUB-STRUCT-2 PIC 9(8).

And the following code:


      * 3RD TEST:                                         
           MOVE 112011   TO SUB-STRUCT-1.                 
           MOVE 20100113 TO SUB-STRUCT-2.                 
           MOVE SUB-STRUCT-1N TO FIELD-A OF STRUCT-1      
           MOVE SUB-STRUCT-2N TO FIELD-B OF STRUCT-1      
           DISPLAY "SUB-STRUCT-1  : " SUB-STRUCT-1        
           DISPLAY "SUB-STRUCT-2  : " SUB-STRUCT-2        
           DISPLAY "FIELD-A       : " FIELD-A OF STRUCT-1 
           DISPLAY "FIELD-B       : " FIELD-B OF STRUCT-1 

Beware: Moving character data into a COMP-3 field may give you the dreaded SOC7 data exception abend when the receiving item is referenced. This is because not all bit patterns are valid COMP-3 numbers.

NealB
Man, this takes me back. I remember when we wanted to look at the last byte of packed decimal fields, because an "04" meant somebody had moved in a value with an EBCDIC space.
David Thornley
@David Thornley. Close... EBCDIC space is hex "40". Today we use use an `IF NUMERIC` test on packed decimal fields to check for that sort of thing. Something that confuses many programmers is that the `MOVE` doesn't blow up, but any computational reference to the field after that ends up giving a data exception abend (SOC7 in IBM land). Most people expect the `MOVE` to blow them up.
NealB
@NealB: Not just close: back in the day, when we packed fields, the last byte had the nybbles swapped, so a string ending 404040 hex would wind up as a packed decimal ending 4404 hex. (This wasn't actually COBOL, but the IBM 360 was specifically designed to run COBOL, having a single ASM instruction that did a formatted MOVE, so I figure my ASM experience is slightly relevant here.)
David Thornley
+1  A: 

You have 2 Issues.

COBOL has several Numeric Data Structures. Each has its own set of rules.

For PACKED DECIMAL ( COMP-3 )
• The numeric components of the PIC clause should ALWAYS add up to an ODD number. • The decimal marker “V” determines the placement of the decimal point. • The individual element MOVE and math functions will maintain the decimal value alignment – both high and low level truncation is possible • Numeric data type conversion (zone decimal to packed & binary to packed) is handled for you.

e.g. S9(5)V9(2) COMP-3.
including the 2 decimal positions> Length is calculated as ROUND UP[ (7 + 1) / 2] = 4 bytes

     S9(6)V9(2) COMP-3.                                            

including the 2 decimal positions > Length is calculated as ROUND UP[(8 + 1) / 2] = 5 bytes But the 1st ½ byte is un-addressable

The last ½ byte of the COMP-3 fields is the HEXIDECIMAL representation of the sign.
The sign ½ byte values are C = signed positive D = signed negative F = unsigned (non COBOL).

S9(6)V9(3) COMP-3 VALUE 123.45. Length is calculated as ROUND UP[(9 + 1) / 2] = 5 bytes
Contains X’00 01 23 45 0C’
Note the decimal alignment & zero padding.


Group Level MOVE rules

COBOL Data field structures are define as hierarchical structures.

The 01 H-L group field – & any sub-group level field –

  1. Is almost always an implied CHARACTER string value
  2. If an individual element field is a 01 or 77 level – then it can be numeric.
  3. Individual element fields defined as a numeric under a group or sub-group level will be treated as numeric if referenced as an Individual element field.
  4. Numeric rules apply. o Right justify o decimal place alignment o pad H-L (½ bytes) with zeros o Numeric data type conversion

The receiving field of a MOVE or math calculation determines if a numeric data conversion will occur.

Numeric Data Conversion If you MOVE or perform a math calculation using any sending field type (group or element) to any receiving individual element field defined using a numeric PIC clause --- then numeric data conversion will occur for the receiving field. S0C7 abends occur when non-numeric data is MOVE ‘d to a receiving numerically defined field OR when math calculations are attempted using non-numeric data.

No Numeric Data Conversion If you move any field type (group or element) to any group or sub-group level field then there will be NO numeric data conversion.
• Character MOVE rules apply.
• Left Justify & pad with spaces.

This is one of the primary causes of non-numeric data in a numerically defined field.

One of the primary uses of a sending group level MOVE containing numeric element fields to a receiving group level containing numeric element fields (mapped identically) is for re-initializing numeric element fields using 1 MOVE instruction.

A Clear Mask – or – a data propagation MOVE is also possible for table clears - where the table group level is greater than 255 bytes.