When initializing the following variables:
01 BATCH-REC.
03 BATCH-VERSION PIC X(2).
03 BATCH-FIELDS PIC X(682).
03 BATCH-REC-01 REDEFINES BATCH-FIELDS.
05 B01-OH-DTL-REC.
07 B01-PE-ID PIC X(12).
07 B01-PMT-DISC-TERMS PIC S9(4) COMP.
07 B01-PMT-DISC-AMT PIC S9(18) COMP.
using the command
INITIALIZE BATCH-REC.
the variables B01-PMT-DISC-TERMS is initialized to value +08224 and B01-PMT-DISC-AMT is initialized to +314885530818453536.
What could the reason be? Would it be a good idea to MOVE a blank space to those variables after initializing? I dont want to change that BATCH-REC code to add a default value on them.
The INITIALIZE statement will not initialize redefined fields. If you want the redefined fields to be initialized, you must identify them in some way. For example,
INITIALIZE BATCH-VERSION BATCH-REC-01
This will initialize the elementary fields to SPACES or ZEROS depending on their PICTURE. BATCH-FIELDS will not be initialized.
Item 3, below applies, in this case. From the 2002 standard for INITIALIZE:
5) The receiving-operand in each implicit MOVE or SET statement is determined by applying the following steps in order:
a) First, the following data items are excluded as receiving-operands:
Any identifiers that are not valid receiving operands of a MOVE statement, except data items of category data-pointer, object-reference, or program-pointer.
If the FILLER phrase is not specified, elementary data items with an explicit or implicit FILLER clause.
Any elementary data item subordinate to identifier-1 whose data description entry contains a REDEFINES or RENAMES clause or is subordinate to a data item whose data description entry contains a REDEFINES clause. However, identifier-1 may itself have a REDEFINES clause or be subordinate to a data item with a REDEFINES clause.
In this case I think you will find your INITIALIZE statement did initialize your PIC X data to spaces. The value you have for B01-PMT-DISC-TERMS is x'2020' and the value for B01-PMT-DISC-AMT is x'2020202020202020' with the leading digit cut off, possibly due to reporting of the value being limited to the picture clause of 18 digits.
Regardless, I agree with #RickSmith and believe he is correct in his solution to your problem.
Related
Moving data to COMP-3 fields after UNSTRING.
UNSTRING is working fine but I am not able to move data to COMP-3 fields without an S0C7 data exception abend.
I think it is an issue with storing data.
Below is my COBOL program.
IDENTIFICATION DIVISION.
PROGRAM-ID. ADDPROG.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 VALUEA PIC X(20) VALUE '64.99|64.99'.
01 NOA PIC S9(9)V9(02).
01 NOB PIC S9(9)V9(02).
01 NOC PIC S9(9)V99 COMP-3.
01 NOD PIC S9(9)V99 COMP-3.
PROCEDURE DIVISION.
000-MAIN.
DISPLAY "EARLIER".
DISPLAY 'NOA-' NOA.
DISPLAY 'NOB-' NOB.
DISPLAY "AFTER".
UNSTRING VALUEA
DELIMITED BY '|'
INTO NOA,NOB.
DISPLAY 'NOA-' NOA.
DISPLAY 'NOB-' NOB.
MOVE NOA TO NOC.
MOVE NOB TO NOD.
DISPLAY 'NOC-' NOC.
DISPLAY 'NOD-' NOD.
STOP RUN.
Output I am getting after compiling.
Please let me know is there any other way to move data to COMP-3 fields or to avoid this error.
Your code has two main problems. To see them you first have to understand that your UNSTRING into NOA and NOB works like any other character-to-character MOVE.
So it starts from the left and moves character after character until one field ends and if necessary adds some blanks to fill up the receiving field.
So problem one is that NOA contains the value left-justified while according to your PIC-clause it should be right-justified, so you would need an intermediate PIC X(12) JUSTIFIED RIGHT field that you UNSTRING to.
The second problem that is causing the S0C7 is that your PIC-clause does not include a decimal-point. The V specifies the implied position of the decimal point but it would not show on output nor is it handled correctly when parsing the field-contents. To have a field that correctly handles the decimal point you should have a PIC S9(9)V.9(02).
Please also see this question.
Like piet.t said, the UNSTRING statement is like a alphanumeric move. Therefore my suggestion is to:
make NOA and NOB be alphanumeric (PIC X(12)), and
change your move statements to include WITH CONVERSION so that it will convert the numeric data in the alphanumeric field into COMP-3.
Your decimal data field are wrong just have . Like 01 NOA PIC S9(9).(02) In them! Same with noc variabile then it should run.
To move data from a numeric field to a COMP-3 field, you need to make sure that the data in the numeric field is valid for the COMP-3 field. A COMP-3 field stores packed decimal data, which means that the digits of the number are packed into two-digit decimal fields. The decimal point is not stored, and the sign of the number is stored in the last nibble of the field.
I have written a code to match the date given by user(instream data) with the date mentioned in an input file. When the date matches, the record is moved to an output file. The program ran successfully. Now i am inserting a header in output file by declaring a variable 'header' in working-storage section, moving the 'header' field to output record and writing the output record. Though it is running successfully i have a doubt. I looked for it everywhere but unable to find it. The problem is-
The concept of buffer tells us that while declaring File Description(FD) it creates a structure. The file description(FD) given with all the records and fields creates a buffer structure. Now all the read/write operation happens through it.
If a program processes more than one file, a record buffer must be defined for each file.
To process all the records in an INPUT file, we must ensure that each record instance is copied from the file, into the record buffer, when required.
To create an OUTPUT file containing data records, we must ensure that each record is placed in the record buffer and then transferred to the file.
To transfer a record from an input file to an output file we must read the record into the input record buffer, transfer it to the output record buffer and then write the data to the output file from the output record buffer.
So when i am giving the date separately and moving it to the output record it is SURELY not going into that buffer which i created using FD in output record. So how is it going there?? If it is creating its own buffer then all data can be moved directly, what is the need of declaring FD??
This is the link to see the concept of buffer
[1]: http://www.csis.ul.ie/cobol/course/SequentialFiles1.htm
This is my code as given below-JUST EMPHASIZE ON STATEMENTS IN SLASHES
IDENTIFICATION DIVISION.
PROGRAM-ID. TXNRPT02 .
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT D01-TXN-FILE ASSIGN TO DETLFILE
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS WS-INSERT-FILE-STATUS1.
SELECT D02-TXN-FILE ASSIGN TO DATEOUT
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS WS-INSERT-FILE-STATUS2.
DATA DIVISION.
FILE SECTION.
FD D01-TXN-FILE. // CREATES A BUFFER
01 D01-TXN-REC.
05 TXN-DATE PIC 9(8).
05 FILLER PIC X(1).
05 TXN-NUMBER PIC 9(5).
05 FILLER PIC X(1).
05 SBACCT-CODE PIC 9(5).
05 FILLER PIC X(1).
05 TXN-AMOUNT PIC 9(5)V9(2).
05 FILLER PIC X(52).
FD D02-TXN-FILE. //CREATES A BUFFER STRUCTURE IN OUTPUT FILE
01 D02-TXN-REC.
05 TXN-DATE1 PIC 9(8).
05 FILLER PIC X(1).
05 TXN-NUMBER1 PIC 9(5).
05 FILLER PIC X(1).
05 SBACCT-CODE1 PIC 9(5).
05 FILLER PIC X(1).
05 TXN-AMOUNT1 PIC 9(5)V9(2).
05 FILLER PIC X(52).
WORKING-STORAGE SECTION.
01 HEAD1 // declaring header
02 FILLER PIC X(20).
02 TEXT PIC X(40) VALUE 'REPORT OF BANK'
01 FILE-STATUS PIC X(02) VALUE '00'.
88 EOF VALUE '10'.
88 SUCCESS VALUE '00'.
01 WS-INSERT-FILE-STATUS1 PIC X(2).
01 WS-INSERT-FILE-STATUS2 PIC X(2).
01 WS-DATE PIC 9(8). // DATE TO BE ACCEPTED FROM INSTREAM DATA
PROCEDURE DIVISION.
MAIN-PARA.
ACCEPT WS-DATE.
PERFORM OPEN-PARA.
PERFORM INIT-PARA.
PERFORM PROCESS-PARA UNTIL EOF.
PERFORM CLOSE-PARA.
STOP RUN.
OPEN-PARA. // OPENS INPUT AND OUTPUT FILES
OPEN INPUT D01-TXN-FILE.
DISPLAY 'INFILE OPEN STATUS' , WS-INSERT-FILE-STATUS1.
OPEN OUTPUT D02-TXN-FILE.
DISPLAY 'OUTFILE OPEN STATUS' ,WS-INSERT-FILE-STATUS2.
INIT-PARA. // INITIALIZES BOTH RECORDS
INITIALIZE D01-TXN-REC.
INITIALIZE D02-TXN-REC.
PROCESS-PARA.
MOVE HEAD1 TO D02-TXN-REC. // MOVING HEADER TO OUTPUT RECORD
WRITE D02-TXN-REC. // WRITING THE HEADER
READ D01-TXN-FILE
AT END MOVE '10' TO FILE-STATUS
NOT AT END PERFORM OPPO-PARA
END-READ.
OPPO-PARA. //PERFORMS EQUAL OPERATION ON BOTH DATES
IF WS-DATE = TXN-DATE
MOVE D01-TXN-REC TO D02-TXN-REC
WRITE D02-TXN-REC
END-IF.
CLOSE-PARA. // CLOSING BOTH FILES
CLOSE D01-TXN-FILE, D02-TXN-FILE.
DISPLAY 'INFILE CLOSE STATUS' , WS-INSERT-FILE-STATUS1.
DISPLAY 'OUTFILE CLOSE STATUS' , WS-INSERT-FILE-STATUS2.
I think you are over-complicating things.
In the FILE SECTION you logically connect a record-layout to a file that will be read, or to a record which will be written (to a file).
No storage is allocated in your COBOL program by the definition of the FD or any 01-levels subordinate to an FD. You simply establish a "map" which will be used to understand the data read from a file, or to use to construct the data which you will write to a file.
When you OPEN a file, some run-time code does that work behind the scenes, and will make the address of the first byte of your record layout(s) under the FD equal to the first byte of the piece of storage that will be used as the "buffer".
A "buffer" in this context is just a piece of storage which is the same size as your BLKSIZE and which will be used, without you having to be aware of it, to store records before they are actually written to the physical output file.
What happens when you WRITE a record is that the record-pointer simply gets changed to the first available byte after the current record.
It is similar when you read.
Although installation-dependent, mostly you will have the default number of buffers for a simple sequential file, which is five. Once a buffer is full the, for an output file, the IO-subsystem will be told it has data available for writing, and the filling will continue, asynchronously, with the next buffer area. What this does is reduce the amount of time your COBOL program is waiting for IO to complete.
It is similar, which obvious reversals, for the READ of a sequential file.
As a beginner, you don't need to know what the buffering is doing. Just keep it conceptually simple. You OPEN, you READ, the record is "under" the FD. You continue doing that until end-of-file, then you CLOSE. At the same time (usually) you OPEN, you WRITE, and you CLOSE at the end. What gets written is the data that is under the FD for the output file.
Also review READ ... INTO ... and WRITE ... FROM .... The concept is the same, it is just that COBOL will "move" the data to the FD for you, rather than you having detailed record-layouts under the FD. Whether you use READ file or READ file INTO record-layout is usually down to local standards for your site - do it the way your team does it.
You have now added some code to your Question.
First thing, you are writing your header inside a loop. You will get one header per record, which is probably not what you want.
Secondly, you've changed to use the FILE STATUS but not fully grasped how it works yet. You don't need the AT END/NOT AT END. The COBOL IO will maintain the FILE STATUS field. When end-of-file is identified by the COBOL run-time the FILE STATUS field will be set to "10", "automatically" as far as you are concerned.
Thirdly, review your use of INITIALIZE. There is never any point in INITIALIZE on an input record. READ always advances the record-pointer. The storage INITIALIZEd is the storage before the record you read. Even if it was not, what is the point of INITIALIZE, just to read a record over the top of the initialised storage? Same with your output.
All that your use of INITIALIZE is doing is using CPU time. Yes, it is not at all uncommon that this happens, but that is no excuse for you to pick up bad habits as well.
Is it possible to assign a string of hexadecimal to a comp or binary declared variable?
Example:
01 COMP-VAR PIC 9(4) COMP.
MOVE X'04D2' TO COMP-VAR.
should output +1234.
Edited:
Sorry for the lack of the information, I just gave an example. The real scenario is that the data will come from an external source, a dataset. I need to store the data in an alphanumeric variable before I move it to a comp declared variable. My problem is that the data is incorrect when I move the alphanumeric data to the comp variable. Your help is very much appreciated.
I think you are looking for REDEFINES. Redefine the binary value as character, do the assignment
which will not violate any of the assignment rules and then use the binary representation in
subsequent operations. This program illustrates your example:
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01.
02 COMP-VAR PIC 9(4) COMP.
02 COMP-X REDEFINES COMP-VAR PIC X(2).
PROCEDURE DIVISION.
MOVE X'04D2' TO COMP-X
DISPLAY COMP-VAR
GOBACK
.
This displays 1234.
The larger question is why would you need to do this? I suspect that you are attempting to
read a file with multiple record formats in it. Based on some common record identifier you
need to read part of the record as character or as binary. Typically this is done a little
differently in COBOL.
Here is a larger example of what I mean. Suppose you have an input
record that is 3 bytes long. When the first byte is a 'B' it is telling you that the next two bytes should be
treated as a binary (COMP) value. When the first byte is an 'X' you need to read the next two
bytes as text (X) data. As an example this is what two records might look like:
X'E7C1C2'
X'C204D2'
The first record is a text record containing the value 'AB' (EBCDIC). The second record is binary containing
the value 1234. The program to process these records might look something like:
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 INPUT-RECORD.
02 REC-TCD PIC X.
88 REC-TCD-BIN VALUE 'B'.
88 REC-TCD-CHAR VALUE 'X'.
02 REC-DUMMY PIC X(2).
02 REC-COMP-VAR REDEFINES REC-DUMMY PIC 9(4) BINARY.
02 REC-CHAR-VAR REDEFINES REC-DUMMY PIC X(2).
PROCEDURE DIVISION.
*
* THIS IS A CHARACTER RECORD
*
MOVE X'E7C1C2' TO INPUT-RECORD
PERFORM DISPLAY-INPUT-RECORD
*
* THIS IS A BINARY RECORD
*
MOVE X'C204D2' TO INPUT-RECORD
PERFORM DISPLAY-INPUT-RECORD
GOBACK
.
DISPLAY-INPUT-RECORD.
EVALUATE TRUE
WHEN REC-TCD-BIN
DISPLAY 'REC TYPE: ' REC-TCD
' BINARY DATA: ' REC-COMP-VAR
WHEN REC-TCD-CHAR
DISPLAY 'REC TYPE: ' REC-TCD
' CHAR DATA : ' REC-CHAR-VAR
WHEN OTHER
DISPLAY 'UNKNOWN RECORD TYPE: ' REC-TCD
END-EVALUATE
.
The output from this program is:
******************************** Top of Data ***********************************
REC-TYPE: X CHAR DATA : AB
REC-TYPE: B BINARY DATA: 1234
******************************* Bottom of Data *********************************
Look at the INPUT-RECORD definition. The first byte determines how the rest of the
record is to be intrepreted. REC-DUMMY is generally defined as a "generic" buffer area
to be subsequently redefined. In the case of variable length input records, REC-DUMMY
is defined to be as long as the longest record variant so the subsequent REDEFINEs of it
do not "upset" the compiler. All data items following REC-DUMMY begin with the same level
number (02 in the example) and REDEFINE it to the the appropriate format. Subsequent
processing uses whatever record redefinition is appropaiate based on the value in REC-TCD.
IF AWA-REQ-DATE < WS-JULIAN-DATE
MOVE VAR1 to VAR2
The AWA-REQ-DATE is a binary integer i.e. PIC S9(09) COMP, whereas Julian date is PIC X(10) VALUE SPACES.
Both have Julian date inside them like 2013031 & 2013099.
This gives:
ERROR:REQ-DATE (BINARY INTEGER)" was compared with "WS-JULIAN-date (ALPHANUMERIC)". Discarded
Can I compare then with converting one of them to other format right here in code?
All your four-digit-year Julian dates will contain seven digits. They are dates, so naturally are positive.
It is unclear why you have a nine-digit, signed, binary to hold such or date. Nor a 10-byte alphanumeric. It is also unclear why this should have an initial value of SPACE.
01 WS-JULIAN-DATE VALUE SPACE.
05 WS-JULIAN-DATE-NUM PIC 9(7).
05 FILLER PIC XXX.
This assumes all your WS-JULIAN-DATE values are left-aligned.
IF AWA-REQ-DATE < WS-JULIAN-DATE
MOVE VAR1 to VAR2
END-IF
Hopefully VAR1 and VAR2 are just sample names for the question. If not, please make them meaningful, as it will make it much easier for the next person reading the program to understand. And that might be you.
If the values of WS-... are not guaranteed to be NUMERIC, test them for NUMERIC and take appropriate action (according to your spec) if they are not.
The nine-digit binary will potentially generate extra code beyond what is needed.
Another possibility is:
01 WS-AWA-REQ-JULIAN-DATE VALUE SPACE.
05 WS-AWA-REQ-JULIAN-DATE-NUM PIC 9(7).
05 FILLER PIC XXX.
MOVE AWA-REQ-DATE TO WS-AWA-REQ-JULIAN-DATE-NUM
IF WS-AWA-REQ-JULIAN DATE < WS-JULIAN-DATE
MOVE VAR1 to VAR2
END-IF
Which you choose can depend on what else you are doing with the fields.
Also, if one is "invariant", convert that to the same format as the variable one, once only.
In the various ISO/ANSI COBOL standards, comparing alphanumeric (PIC X) and numeric (PIC 9) is like comparing apples and oranges. There are defined rules. Of course, each compiler has different ways of interpreting the standard. Therefore, you are best off converting one of the fields to the other format and comparing those. Bill Woodger has some good comments about which field to convert, and how.
In summary, you should always compare like data types. For numeric items, it's best if you can compare the same COMP format, but sometimes this can't be done. If that is the case, you need to read your compiler documentation to see how comparisons are performed between different computational types, and any gotchas (such as COMP-4 and COMP-5 in IBM's Enterprise COBOL).
The answer probably depends on which compiler you are using. On GNU Cobol, the comparison works after applying FUNCTION NUMVAL to the Julian (text) date.
As the error message is describing: a numeric value PIC S9(9) COMP cannot be compared to a string PIC X(10).
A COMP variable is a system dependent, numeric representation of the value. There are variations to the internal representation (binary, BCD,...) used for COMPutation. The value of your date is,depending on the machine though, internally represented as: 0011110 10110111 01100111
Display variables are storing each position of your variable according to an encoding standard (ASCII, EBCDIC, UNICODE). Again depending on your machine and the encoding table, the representation of your variable might be: 00110010 00110000 00110001 00110011 00110000 00111001 00111001
I do some guessing here in order to address the underlying problem
First guess: The alpha definition PIC X(10) looks like the date is in printing format and should contain separators in order to make it 10 characters long
21.02.2014
123456789A
Such a variable shouldn't hold a julian date after all and you probably need a date comparing function.
Second guess: for some displaying reason, you want to have a variable of 10 characters long, holding the julian date in the first 7 characters. In this case, I'd define a structure and you can keep your comparison as is:
01 WS-JULIAN-DATE-PRINT VALUE SPACE.
05 WS-JULIAN-DATE PIC 9(7).
05 FILLER PIC X(3).
I have the following variable in COBOL program which gets its value from a file, when it is read:
01 Employee-number PIC 09(8) comp
01 Employee-number-x redefines
Employee-number PIC x(04)
I have another variable in the same program:
01 D-element-number PIC 9(04)
Now,
Move Employee-number to D-element-number
Then I write this D-element-number to a file
value read from input file is :
0013
0024
so this value comes to Employee-number and Employee-number-x and I move this value to D-Element-number and write this variable to a output file.
But I get this in the output file:
4660
FFFF
4660
4660 is the decimal equivalent of X'1234'
But I want to see something like:
1234
FFFF
1234
How can I achieve this ?
I am allowed to change the definition of D-element-number but nothing else.
Assuming that when you have X'00001234' you want C'00001234', have a look here. http://ibmmainframes.com/viewtopic.php?p=234231#234231
Ignore the rest of the discussion for now, just concentrate on that post.
This is the key part:
PERFORM UNTIL X-WS-1000 > X-WS-1000-MAX
MOVE WS-1000-BYTE-TBL (X-WS-1000)
TO WS-PACKED-X (1:1)
MOVE WS-PACKED TO WS-DISPLAY
MOVE WS-DISPLAY-X TO WS-2000-BYTE-TBL (X-WS-2000)
SET X-WS-1000 UP BY 1
SET X-WS-2000 UP BY 1
END-PERFORM
You need the exact storage definitions to go with it (don't "correct" anything).
It works by getting the compiler to use the "unpack" instruction (UNPK). This one is working one byte at a time, so simple to explain.
X'12' (an example on-byte field) is put in a two-byte field. X'12ii' (where the value of ii is "irrelevant").
UNPK will then turn this "packed" number into a "zoned" number. A "Zone" is the first four bts of a byte, and for a Zoned number, the four bits are all set to one. So you get an F. Then you get the left-most digit from the first byte. Then you get the second output byte, first four bits set to F, then the second input digit.
Then the UNPK continues with the final byte, which contains one irrelevant digit, and an irrelevant sign. For a Zoned number, the sign and right-most digit occupy the same byte (the sign in the zone) so you get a whole byte of irrelevance.
X'12' -> X'12ii' -> X'F1F1ii'.
The first two bytes of the three-byte output are C'12'.
Nos, what is all fine for numbers, but letters make a mess:
X'AB' -> X'ABii' -> X'FAFBii'
Although F and a digits gives a displayable number, for F and a letter, the result does not mean much directly.
Now the INSPECT ... CONVERTING comes to the rescue: FA gets translated to C'A' (X'C1), and the same for the letters through to F.
Your results after the CONVERTING will be C'AB'.
Should give you enough to work on.
There are other methods, but this is a fair COBOL approximation to the classic Assembler technique with UNPK and a TRANSLATE (TR) and a table of translation values.
If you use your favourite search engine. you should be able to fine more methods, using calculation (more than one), table-lookups, I've even seen a 256-WHEN EVALUATE that "works", but I guess it is a little on the "slow" side.
Thinking further, you actually have a BCD (Binary Coded Decimal) don't you? This is a Packed Decimal, without the sign. You don't have any alphas in your field.
This is even simpler to convert.
01 the-converted-value PACKED-DECIMAL PIC 9(8)V9 VALUE ZERO.
01 FILLER REDEFINES the-converted-value.
05 the-binary-value PIC X(4).
05 FILLER PIC X.
MOVE Employee-number-x TO the-binary-value
MOVE the-converted-value TO D-element-number (with Gilbert's correction to PIC 9(8)).
The "decimal place" is the ii, the ignore value and ignore sign. You no longer need the INSPECT ... CONVERTING ... as you only have numeric digits. If you have a BCD...
A really good way for you to have answered your own question would have been to find out how the number was created in the binary field in the first place.
Didn't try this, but I think it might work:
01 WN-GROUP.
05 Employee-number PIC 9(8) comp.
05 PACKED-ZERO PIC 9(1) COMP-3 VALUE ZERO.
01 WN-PACKED redefines WN-GROUP PIC 9(9) COMP-3.
01 WN-UNPACKED PIC 9(9).
Then in your procedure:
MOVE your-number TO Employee-number
MOVE WN-PACKED TO WN-UNPACKED.
And finally you can move or display WN-PACKED(1:8).