I am using VSAM files for the first time and am having a ton of trouble with the ORGANIZATION part of the VSAM definition.
I thought that the key is what Cobol uses to search on the file.
Question: Why is the organization clause not working?
Code Here:
SELECT SW24VF01 ASSIGN TO UT-S-INPUT2
ORGANIZATION IS INDEXED
ACCESS IS RANDOM
RECORD KEY IS MY-PROV-KEY-24
FILE STATUS IS SW24VF01-STAT.
SELECT SS45VF90 ASSIGN TO UT-S-INPUT3
ORGANIZATION IS INDEXED
ACCESS IS RANDOM
RECORD KEY IS MY-PROV-KEY-45
FILE STATUS IS SS45VF90-STAT.
FD SW24VF01.
01 MY-PROV-KEY-24 PIC X(09).
01 FILLER PIC X(1991).
FD SS45VF90.
01 MY-PROV-KEY-45 PIC X(09).
01 FILLER PIC X(1991).
Error Here:
32 IGYGR1208-E The "ORGANIZATION" clause for file "SW24VF01" specified an
organization specified in the assignment-name. An organiz
37 IGYGR1208-E The "ORGANIZATION" clause for file "SS45VF90" specified an
organization specified in the assignment-name. An organiz
You need to get hold of a copy of the Enterprise COBOL Language Reference for the version of Enterprise COBOL you are using. This will most likely be V3.4, V4.1 or V4.2, possibly V5.1 (released in June last year).
For this particular question, any version will do, but going forward it is good to know where to find the one specific to the version of COBOL you are using. Also get the Programming Guide as well.
An internet search for IBM Enterprise COBOL for z/OS library should get you to a page where you can easily locate the correct one.
Locate the ASSIGN clause in the Language Reference.
Format: assignment-name for QSAM files
label-S-name
Format: > assignment-name for VSAM sequential file
label-AS-name
Format: > assignment-name for line-sequential, VSAM indexed, or VSAM relative
file
label-name
label- Documents (for the programmer) the device and device class to
which a file is assigned. It must end in a hyphen; the specified value
is not otherwise checked. It has no effect on the execution of the
program. If specified, it must end with a hyphen.
S- For QSAM files, the S- (organization) field can be omitted. AS- For
VSAM sequential files, the AS- (organization) field must be specified.
**For VSAM indexed and relative files, the organization field must be omitted.**
name
A required field that specifies the external name for this file.
Thus, a VSAM KSDS or RRDS requires that the ASSIGN contains very limited information, a label, which is syntax-checked but otherwise not used.
In the past, information in the ASSIGN would have had many more meanings. A different COBOL on a different Operating System may have different requirements. For Enterprise COBOL for z/OS, the ASSIGN is very simple.
In the Programming Guide you will find a Chapter on processing VSAM files. It will assist you in this task.
From that Chapter, an example SELECT statement for a KSDS:
SELECT R-FILE
ASSIGN TO RELATIVE-FILE
ORGANIZATION IS RELATIVE
ACCESS IS RANDOM
RELATIVE KEY IS RFILE-RELATIVE-KEY
FILE STATUS IS FSTAT-CODE VSAM-CODE.
You should take note of that second data-name for the FILE STATUS. This is an extension to the simple FILE STATUS, just for VSAM files. It will contain diagnostic information when you have a non-zero FILE STATUS. I suggest you code it, it will make things easier for you.
Related
I'm very new to COBOL. I'm following the tutorials that came with Micro Focus and I can't seem to get the example to work right. I'm trying to print -123.45 and I keep getting the following,
I looked up a number of posts on here and they don't address my problem. I'm using Micro Focus' Visual COBOL in Eclipse. Here's my code,
program-id. tictac as "tictac".
environment division.
configuration section.
data division.
working-storage section.
01 WS-NUM3 PIC S9(3)V9(2) VALUE -123.45.
procedure division.
Display WS-NUM3.
goback.
end program tictac.
The V in your picture clause is an implied decimal point. I think you want a field with PIC -999.99, where the . is an explicit decimal point, for its picture clause.
You might think of this as COBOL making a distinction between how a variable is defined and how it is shown. Sort of like a format string in printf is just specifying how to show a variable, not how it is defined. Though in both cases the definition and how it is shown have to match up to a certain extent.
Choosing the right picture clause for a numeric field is important; if you're doing calculations it can have a significant performance impact.
So it's common to have a field with a definition such as...
PIC 9(4)V99 COMP-3
...and a corresponding field for output purposes such as...
PIC ZZZ9.99
...so that computations can be done on the first, and when displaying the field is necessary one uses a MOVE statement to copy the contents of the first to the second.
I have a fairly basic Cobol program I'm using to learn about record structures. I'm noticing strange behaviour with gnucobol when passing signed numeric values as part of the record in an ACCEPT statement.
The program is defined as follows:
IDENTIFICATION DIVISION.
PROGRAM-ID. TEST.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Account.
02 Name PIC X(5) VALUE SPACES.
02 Balance PIC S9999V999 VALUE ZEROES.
PROCEDURE DIVISION.
MAIN.
DISPLAY "Enter account details:"
ACCEPT Account.
DISPLAY "Balance is:"
DISPLAY Balance.
STOP RUN.
The behaviour is as follows:
Enter account details:
AAAAA-123.456
Balance is:
+-123.045
I assume this is due to how the value is stored in raw memory.
Is this generally what most cobol compilers do? Is there a way to get cobol interpreting the signed value properly?
I assume this is due to how the value is stored in raw memory.
yes
Is this generally what most cobol compilers do?
a guess: yes (the actual display will vary, but I'm sure most COBOL environments won't do what you seem to want them, at least this way)
Is there a way to get cobol interpreting the signed value properly?
Yes, but there are "COBOL" things to do:
store data in internal format (like you did: signed value with implied 3 decimal positions), but for ACCEPT and likely also DISPLAY use a format that actually has the data as you want, for example a PIC +ZZZ9.999$, for some details look at this answer
never ACCEPT a record, either split into multiple ACCEPT or use a single one with accepting a screen-name, not a record name --> use the SCREEN SECTION for entering the data, this will provide you with two separate fields and with most COBOL environments reasonable input validation.
I'm attempting to output the following row using DISPLAY and am getting the correct result in Micro Focus COBOL in Visual Studio and the Tutorialspoint COBOL compiler, but something strange when running it on a z/OS Mainframe using IBM's Enterprise COBOL:
01 W05-OUTPUT-ROW.
05 W05-OFFICE-NAME PIC X(13).
05 W05-BENEFIT-ROW OCCURS 5 TIMES.
10 PIC X(2) VALUE SPACES.
10 W05-B-TOTAL PIC ZZ,ZZ9.99 VALUE ZEROS.
05 PIC X(2) VALUE SPACES.
05 W05-OFFICE-TOTAL PIC ZZ,ZZ9.99 VALUE ZEROS.
It appears in Enterprise COBOL that the spaces are being ignored, and is adding an extra zero-filled column even though the PERFORM VARYING and DISPLAY code is the exact same in both versions:
PERFORM VARYING W02-O-IDX FROM 1 BY 1
UNTIL W02-O-IDX > W12-OFFICE-COUNT
MOVE W02-OFFICE-NAME(W02-O-IDX) TO W05-OFFICE-NAME
PERFORM 310-CALC-TOTALS VARYING W02-B-IDX FROM 1 BY 1
UNTIL W02-B-IDX > W13-BENEFIT-COUNT
MOVE W02-O-TOTAL(W02-O-IDX) TO W05-OFFICE-TOTAL
DISPLAY W05-OUTPUT-ROW
END-PERFORM
W13-BENEFIT-COUNT is 5 and never changes in the program, so the 6th column is a mystery to me.
Correct output:
Strange output:
Edit: as requested, here is W02-OFFICE-TABLE:
01 W02-OFFICE-TABLE.
05 W02-OFFICE-ROW OCCURS 11 TIMES
ASCENDING KEY IS W02-OFFICE-NAME
INDEXED BY W02-O-IDX.
10 W02-OFFICE-CODE PIC X(6).
10 W02-OFFICE-NAME PIC X(13).
10 W02-BENEFIT-ROW OCCURS 5 TIMES
INDEXED BY W02-B-IDX.
15 W02-B-CODE PIC 9(1).
15 W02-B-TOTAL PIC 9(5)V99 VALUE ZERO.
10 W02-O-TOTAL PIC 9(5)V99 VALUE ZERO.
and W12-OFFICE-COUNT is always 11, never changes:
01 W12-OFFICE-COUNT PIC 99 VALUE 11.
The question is not so much "why does Enterprise COBOL do that?", because it is documented, as "why do those other two compilers generate programs that do what I want?", which is probably also documented.
Here's a quote from the draft of what became the 2014 COBOL Standard (the actual Standard costs money):
C.3.4.1 Subscripting using index-names
In order to facilitate such operations as table searching and
manipulating specific items, a technique called indexing is available.
To use this technique, the programmer assigns one or more index-names
to an item whose data description entry contains an OCCURS clause. An
index associated with an index-name acts as a subscript, and its value
corresponds to an occurrence number for the item to which the
index-name is associated.
The INDEXED BY phrase, by which the index-name is identified and
associated with its table, is an optional part of the OCCURS clause.
There is no separate entry to describe the index associated with
index-name since its definition is completely hardware oriented. At
runtime the contents of the index correspond to an occurrence number
for that specific dimension of the table with which the index is
associated; however, the manner of correspondence is determined by the
implementor. The initial value of an index at runtime is undefined,
and the index shall be initialized before use. The initial value of an
index is assigned with the PERFORM statement with the VARYING phrase,
the SEARCH statement with the ALL phrase, or the SET statement.
[...]
An index-name may be used to reference only the table to which it is
associated via the INDEXED BY phrase.
From the second paragraph, it is clear that how an index is implemented is down to the implementor of the compiler. Which means that what an index actually contains, and how it is manipulated internally, can vary from compiler to compiler, as long as the results are the same.
The last paragraph quoted indicates that, by the Standard, a specific index can only be used for the table which defines that specific index.
You have some code equivalent to this in 310-CALC-TOTALS: take a source data-item using the index from its table, and use that index from the "wrong" table to store a value derived from that in a different table.
This breaks the "An index-name may be used to reference only the table to which it is associated via the INDEXED BY phrase."
So you changed your code in 310-CALC-TOTALS to: take a source data-item using the index from its table, and use a data-name or index defined on the destination table to store a value derived from that in a different table.
So your code now works, and will give you the same result with each compiler.
Why did the Enterprise COBOL code compile, if the Standard (and this was the same for prior Standards) forbids that use?
IBM has a Language Extension. In fact two Extensions, which are applicable to your case (quoted from the Enterprise COBOL Language Reference in Appendix A):
Indexing and subscripting ... Referencing a table with an index-name
defined for a different table
and
OCCURS ... Reference to a table through indexing when no INDEXED BY
phrase is specified
Thus you get no compile error, as using an index from a different table and using an index when no index is defined on the table are both OK.
So, what does it do, when you use another index? Again from the Language Reference, this time on Subscripting using index-names (indexing)
An index-name can be used to reference any table. However, the element
length of the table being referenced and of the table that the
index-name is associated with should match. Otherwise, the reference
will not be to the same table element in each table, and you might get
runtime errors.
Which is exactly what happened to you. The difference in lengths of the items in the OCCURS is down to the "insertion editing" symbols in your PICture for the table you DISPLAY from. If the items in the two tables were the same length, you'd not have noticed a problem.
You gave a VALUE clause for your table items (unnecessary, as you would always put something in them before the are output) and this left your "sixth" column, the five previous columns were written as shorter items. Note the confusion caused when the editing is done to one length and the storing done with a different implicit length, you even overwrite the second decimal place.
IBM's implementation of INDEXED BY means that the length of the item(s) being indexed is intrinsic. Hence the unexpected results when the fields referenced are actually different lengths.
What about the other two compilers? You'd need to hit their documentation to be certain of what was happening (something as simple as the index being represented by an entry-number (so plain 1, 2, 3, etc), and the allowing of an index to reference another table would be enough). There should be two extensions: to allow an index to be used on a table which did not define that index; to allow an index to be used on a table where no index is defined. The two logically come as a pair, and both only need to be specific (the first would do otherwise) because the are specifically against the Standard.
Micro Focus do have a Language Extension whereby an index from one table may be used to reference data from another table. It is not explicit that this includes referencing a table with no indexes defined, but this is obviously so.
Tutorialspoint uses OpenCOBOL 1.1. OpenCOBOL is now GnuCOBOL. GnuCOBOL 1.1 is the current release, which is different and more up-to-date than OpenCOBOL 1.1. GnuCOBOL 2.0 is coming soon. I contribute to the discussion area for GnuCOBOL at SourceForge.Net and have raised the issue there. Simon Sobisch of the GnuCOBOL project has previously approached Ideaone and Tuturialspoint about their use of the out-dated OpenCOBOL 1.1. Ideaone have provided positive feedback, Tutorialspoint, who Simon has again contacted today, nothing yet.
As a side-issue, it looks like you are using SEARCH ALL to do a binary-search of your table. For "small" tables, it is likely that the overhead of the mechanics of the generalised binary-search provided by SEARCH ALL outweighs any expected savings in machine resources. If you were to be processing large amounts of data, it is likely that a plain SEARCH would be more efficient than the SEARCH ALL.
How small is "small" depends on your data. Five is likely to be small close to 100% of the time.
Better performance than SEARCH and SEARCH ALL functionality can be achieved by coding, but remember that SEARCH and SEARCH ALL don't make mistakes.
However, especially with SEARCH ALL, mistakes by the programmer are easy. If the data is out of sequence, SEARCH ALL will not operate correctly. Defining more data than is populated gets a table quickly out of sequence as well. If using SEARCH ALL with a variable number of items, consider using OCCURS DEPENDING ON for the table, or "padding" unused trailing entries with a value beyond the maximum key-value that can exist.
I'd be very hesitant about mixing VALUE with OCCURS and re-code the WS as
01 W05-OUTPUT-ROW.
05 W05-OFFICE-NAME PIC X(13).
05 W05-BENEFITS PIC X(55) VALUE SPACES.
05 FILLER REDEFINES W05-BENEFITS.
07 W05-BENEFIT-ROW OCCURS 5 TIMES.
10 FILLER PIC X(02).
10 W05-B-TOTAL PIC ZZ,ZZ9.99.
05 FILLER PIC X(02) VALUE SPACES.
05 W05-OFFICE-TOTAL PIC ZZ,ZZ9.99 VALUE ZEROS.
Perhaps it has something to do with the missing fieldname?
Ah! evil INDEXED. I'd make both ***-IDX variables simple 99s.
My question is pertaining to a file status 23, which according to MicroFocus means that upon my attempt to READ from a .DAT file:
"Indicates no record found."
or
"Indicates a duplicate key condition. Attempt has been made to store a
record that would create a duplicate key in the indexed or relative
file or a duplicate alternate record key that does not allow
duplicates."
I have eliminated the fact that the latter is my issue because I'm allowing duplicates in this case.
The reason I'm stumped is that I'm using a START to navigate to the record inside of my .DAT file, and when I execute a READ just after the START has positioned my file pointer, I get the file status 23.
Here is my code:
900-GET-INST-ID.
OPEN INPUT INST-MST.
MOVE FALL-IN-INST TO INST-NAME-REC.
START INST-MST
KEY EQUAL TO INST-NAME-REC
INVALID KEY
DISPLAY "RECORD NOT FOUND"
NOT INVALID KEY
READ INST-MST
MOVE INST-ID-REC TO WS-INST-ID
END-START.
CLOSE INST-MST.
So when I am running this code my START successfully runs and goes into the NOT INVALID KEY block, and then the very next line executes and my read is null. How can this be if my alternate key (INST-NAME-REC) is actually found inside the .DAT?
I have ensured that my FD picture clauses match exactly in the ISAM Build program and in this program (the reading program).
The second reason you show is excluded not because you allow duplicate keys, but because that error message with that file-status is for a WRITE, and your failure is on a READ.
Here's your problem:
READ INST-MST
Here's how you fix it:
READ INST-MST NEXT
In COBOL 85, the READ statement has two formats. Format 1 is for a sequential read and Format 2 is for a keyed (random) read.
Unfortunately, the minimum READ syntax for both sequential and keyed reads is:
READ file-name
Which means if you use READ file-name the compiler will implicitly treat it as Format 1 or Format 2 depending on your SELECT statement.
READ file-name NEXT RECORD is identical to READ file-name NEXT.
Consult your actual documentation for a full explanation and discovery of possible Language Extensions from the vendor. If you consult closely, the behaviour of READ file-name with no further option depends on the type of file. With a keyed file, the default is a keyed READ. You key field (luckily) does not contain a key that exists, so you get the 23.
Even if it didn't work like that, what would be the point of not using the word NEXT? The compiler always knows what you tell it (which sometimes is not what you think you tell it), but in a situation like this, the human reader can be very unsure. The last thing you want to do when bug-hunting is break off to look at the manual to discover exactly how that behaves, and then try to work it if that behaviour was the one sought by the original coder. The bug? A bug? Intended, but sloppy, code? No-one wants to spend that time, and look, even now, it is you.
A couple of comments on your code.
Look up the FILE STATUS clause of the SELECT. Use it. One field per file. Check after each IO. It'll save you grief.
Once using the FILE STATUS, ditch the imperative parts of the IO statements (the something/NOT something) and replace by tests of the file-status field (using 88s).
It looks like you are OPENing and CLOSEing your look-up file all the time. Please don't. OPEN and CLOSE can be very heavy and time-consuming, so do them once per program per file. If you've done that because of a problem, find a correct resolution to that problem, don't use a hack.
Drop the full-stops/periods except where they are needed. This is COBOL 85, which means for 30 years the number of full-stops/periods required in the PROCEDURE DIVISION have been greatly reduced. Get modern, and take advantage of that, it'll save you Gotcha!s as you copy/paste code, leaving the one which shouldn't be there and changing the way the program behaves.
I have an existing MF COBOL 4.0 program with years of data in a ISAM file but I need to add a new field to the existing file. The record currently has 1208 chars and I need to add another 10 to it.
If I simply put the extra PIC X(10) field in my copybook, it gives me an error.
You need to modify the underlying data file to match your file definition in COBOL. One way to do so would be to define a line of output exactly like what lines of your data look like now, but with an extra Pic x(10) on the end of it. You would then read in your data line by line, and output it to a new location with 10 extra spaces on the end of it. That way your data is 10 characters longer, and you can go back and add that extra Pic x(10) to your main program. It should work after that.
With changing the copybook, you're only changing the representation of the data used in your program. Shouldn't you be restructuring the data source (i.e. the ISAM file) as well?
Late answer, but I thought you might be interested.
I've been working on our Cobol system for over 20 years and we've come across this issue many times.
Changes to the structure of our index files are what we consider a "Major Release". These require specific Conversion programs which:
Rename the physical file, moving it aside to an 'old' file
Open the 'old' version of the file (using a version of the copybook before the change)
Open (create) the 'new' version of the file
Move the contents of each of the 'old' records to a 'new' record and WRITEs it
Of course these conversions require the system to be 'down', hence the reason why they are considered major releases.
If you have files which are likely to have fields added to them in the future, you can add extra FILLER to the end of index file to let you cope with new fields being added. We tend to add a FILLER of 50 or 100. Of course this doesn't help you if you change one of the existing fields, or even the structure of any of the keys.
For file errors, you will want to keep a list handy. I recommend starting with a list you find online, and any time you get an error you cannot figure out in 5 seconds, add a detailed explanation of the resolution so you will have it in your notes the next time it happens. Here are a couple decent lists to start with
http://www.simotime.com/vsmfsk01.htm
http://www.briarcliff.edu/departments/cis/Cobol/Error%20Codes.html
In my list, file status 39 is:
OPEN-CONFLICT-FILE-ATR - The 'open' statement was unsuccessful because a conflict was detected between the fixed file attributes specified for that file in the program. These attibutes include the organization of the file (sequential, relative, or indexed), the prime record key, the alternate record keys, the code set, the maximum record size, and the record type (fixed or variable).
And this is from the personalized note: Check the file that you have assigned to your ddname in your JCL. Especially the length allocation. In your case, you know that the length does not match, since you just changed the program.
There are utilities to reformat datasets, particularly SYNCSORT. Or of course you can write your own.