I am creating an SSIS package to read in unpacked data from a series of copybook files. I am unsure of the correct interpretation of the following field definitions and was hoping someone would know:
FIELD-NAME-1 PIC S9(15)V9(3) COMP-3.
FIELD-NAME-2 PIC S9(3)V9(8) COMP-3.
FIELD-NAME-3 PIC S9(3)V9(6) COMP-3.
The data is stored in fixed width text. The data for the above fields has the following lengths:
FIELD-NAME-1: 19
FIELD-NAME-2: 11
FIELD-NAME-3: 9
I am unsure how to interpret the decimal place and sign.
Any help would be greatly appreciated.
Kind Regards,
Ham
Here is a little different attempt at answering your questions.
PIC S9(15)V9(3) COMP-3 looks like this in the file:
00 00 00 00 00 00 00 00 00 0F
If the value was -4568248.323, it would be:
00 00 00 00 04 56 82 48 32 3D
This doesn't help you, but may help others.
Unpacked the previous value would look like:
F0 F0 F0 F0 F0 F0 F0 F0 F0 F4 F5 F6 F8 F2 F4 F8 F3 F2 D3 (or F3 as the last byte, therefore losing the sign)
This field has 15 (actually 16) digits before the decimal point and 3 after.
Although it only requests 18 digits (15+3), it gets 19 to make it an even length field with the sign (one digit added to the front to make it 10 bytes long on the file). Best practice is to always make packed fields an odd length to avoid this confusion.
** The last letter denotes the sign, C & F are positive, D is negative. For your program, check for negative (D) and if not, treat as positive.
** The 'V' is an implied decimal point. it doesn't exist on the file, but COBOL knows that it's there for rounding and such. You need to programmatically account for it. There is nothing in the file to help you identify where it is or if it even exists.
The other two fields are already odd lengths, so when packed, with the sign, they can be stored in an even length amount of space.
Any other questions, edit your question or ask in the comments and someone will try to answer them for you.
See method getMainframePackedDecimal in http://jrecord.cvs.sourceforge.net/viewvc/jrecord/jrecord/src/net/sf/JRecord/Common/Conversion.java?revision=1.2&view=markup
for an example of converting packed decimal in java (it is part of the jrecord project jrecord.sf.net)
Usually COMP-3 fields consist of BCD digits packed into bytes two at a time, each digit using a nibble (4 bits). The last digit goes in the upper nibble of the last byte. The lower nibble of the last byte has 13 if the number is negative, and something else, (usually 12) if positive. The decimal point is implied.
For example, -1.2 looks like this in hex, the final D is the negative sign.
01 2D
12.345 is:
12 34 5C
Here we go:
PIC is "picture"
S9(15) means a 15 digit numeric signed field: S for sign, 9 is numeric, (15) is length.
V is the decimal position
9(3) is a three digit numeric
and COMP-3 is BCD encoded decimal. Each nybble (half-byte) of the field is a decimal value in binary, so
0b01110110 (duh)
is "76".
18 digits requires 9 bytes, the sign is the low nybble of the low order byte.
Which worries me, those should require 10 bytes.
Here's a nice article on it.
COMP-3 fields length is calculated as number of digits that we need to store + 1 divided by 2. For example to store an numeric field of value 987 we would required 3 +1 divided by 2 = 2 Hence an Comp-3 field of length 2 bytes can store a value of +999 to -999 as the limit.
15 would stored as 01 5C. So the last four bits of the number is used to store the sign of the number that is C or D so "C" represents the positive number and "D" represents the negative number. And each numeric number takes 4 bits to represents themself.
So an 7 digit numeric number would require 7 +1 = 8 / 2 = 4 byte in size. So the comp-3 field of size 4 bytes can store an numeric digits of +999,9999 to -999,9999 digits.
In case of the above question to move the decimal portion of the number need to define an variable which can store only the decimal portion and move the value to that field which would hold just the decimal portion.
like FIELD-NAME-3 PIC S9(3)V9(6) COMP-3.
we need to define a decimal field like DEC-PORTION V9(6) comp-3 and then move the FIELD-NAME-3 to DEC-PORTION to retain the decimal part of the value.
This way we can have the decimal portion of the number separated from the full number.