I work on a mainframe system for which I'm developing code to analyze
files and develop distributions by values in individual fields in
those files. I want to set up a call to a subroutine program that will
look something like this:
CALL subroutine USING field
field-length
distribution-table
The idea is that each row in the table will have a unique value,
followed by a tally. New values will have new rows populated (not
added - each table will be predefined to have a maximum of 50 rows),
while existing rows will only have the tally incremented. From this
you can see the tables will not occupy very much in the way of
storage, no more than a few KB at the most.
Here's the catch -- I want to call the same subroutine program
multiple times for any of a number of fields and associated tables,
some or all of which will have varying field lengths (and by
extension, the table rows will be of varying length as well). Using
some sort of DEPENDING ON clause won't do the trick because I already
know how many rows will exist, just not the length of each row.
I can pass in the field length (as seen above) and from there
dynamically work with the values in the subroutine. What I want to
know is, how do I code the Linkage Section statements? Incidentally,
I'm calling the COBOL program from an Easytrieve program, so I'm not
sure that something like address pointers would work for me. Any and
all help would be appreciated.
Thanks,
John
>Here's the catch -- I want to call the same subroutine program
>multiple times for any of a number of fields and associated tables,
>some or all of which will have varying field lengths (and by
>extension, the table rows will be of varying length as well). Using
>some sort of DEPENDING ON clause won't do the trick because I already
>know how many rows will exist, just not the length of each row.
I don't see why DEPENDING ON won't do the trick.
>I can pass in the field length (as seen above) and from there
>dynamically work with the values in the subroutine. What I want to
>know is, how do I code the Linkage Section statements? Incidentally,
>I'm calling the COBOL program from an Easytrieve program, so I'm not
>sure that something like address pointers would work for me. Any and
>all help would be appreciated.
It looks like you're using an IBM mainframe. So your CoBOL program
will have something like this:
LINKAGE SECTION.
01 PASSED-RECORD.
05 PASSED-LENGTH PIC 9(4) COMP.
05 PASSED-DATA.
10 ...
That length field will be populated by the system.
--
"In no part of the constitution is more wisdom to be found,
than in the clause which confides the question of war or peace
to the legislature, and not to the executive department."
- James Madison
>It looks like you're using an IBM mainframe. So your CoBOL program
>will have something like this:
>
> LINKAGE SECTION.
> 01 PASSED-RECORD.
> 05 PASSED-LENGTH PIC 9(4) COMP.
> 05 PASSED-DATA.
> 10 ...
>
>That length field will be populated by the system.
If you have a maximum size, you might consider just creating a linkage
area that big, then manipulate it however you wish.
To answer an earlier question, yes, it's an IBM mainframe.
I thought about sending it through as just one big area, then chopping
it up as needed, based on the record length (reference modification,
etc.). I won't know my maximum from one file to the next, though -- if
I end up with a definition in the subroutine program that's not big
enough for what's handed down to it, is there any way I can
dynamically point beyond the end of what's defined in my Linkage
Section? I can't say I know, but COBOL does some interesting things
these days.
Thanks again.
[snip]
>> If you have a maximum size, you might consider just creating a linkage
>> area that big, then manipulate it however you wish.
[snip]
>I thought about sending it through as just one big area, then chopping
>it up as needed, based on the record length (reference modification,
>etc.).
As a subtle suggestion to indicate my opinion of this possiblity... NO,
NO, THRICE NO. Some posters to this newsgroup get their panties in a
bunch about REDEFINES or 88s; it is my experience that while reference
modification is a *most* valuable addition to the language I have seen it
used in fashions for 'just this once' that cause difficulties in
maintenance... compare:
IF CUST-HDR-REC AND LOCAL-ZIP-CODE
PERFORM A17258-STATE-TAX-RTN THRU A17258-EX.
... with ...
If WS-Cust-Info-Rec(1:1) = '1' and WS-Cust-ZipCd(1:2) = '02'
Perform State-Tax-Rtn
End-If
>I won't know my maximum from one file to the next, though -- if
>I end up with a definition in the subroutine program that's not big
>enough for what's handed down to it, is there any way I can
>dynamically point beyond the end of what's defined in my Linkage
>Section?
If you end up with a definition in the subroutine program that's not big
enough then I would say that the design is need of revisiting. Look
through what you have and need for now... and double that amount of space.
If double what you need now exceeds the amount of space that can be passed
by a CALL... then redesign is most *definitely* in need of revisiting.
>I can't say I know, but COBOL does some interesting things
>these days.
COBOL has always done some 'interesting things'... have you ever dealt
with a hastily-implemented 66-level at 2:am? Have you ever found that
adding 'just one more file' creates a load module so big that it won't fit
into core? How about finding out the length of a variable-length record
by referring to... oh, folks don't do that any more, do they?
The challenge is in making the code simple.
DD
The OP mentioned he was calling the COBOL subroutine from an
Easytrieve. I'm assuming you have multiple Easytrieves to handle the
different size files. The only suggestion I might make since you want
to have only 1 COBOL subroutine is to code a 32K size area in your
COBOL and Easytrieve modules. Populate the 32K area with your table
and send it and the "real" length to the subroutine.
If your files or tables ever exceed 32k obviously you'd have to change
it in all of the Easytrieves and the subroutine but it would be a
simple 1 line change everywhere.
Regards,
////
(o o)
-oOO--(_)--OOo-
"He who laughs last thinks slowest."
-- Steven Wright
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Remove nospam to email me.
Steve
[snip]
>>>I won't know my maximum from one file to the next, though -- if
>>>I end up with a definition in the subroutine program that's not big
>>>enough for what's handed down to it, is there any way I can
>>>dynamically point beyond the end of what's defined in my Linkage
>>>Section?
>>
>>If you end up with a definition in the subroutine program that's not big
>>enough then I would say that the design is need of revisiting. Look
>>through what you have and need for now... and double that amount of space.
>>
>>If double what you need now exceeds the amount of space that can be passed
>>by a CALL... then redesign is most *definitely* in need of revisiting.
>>
>>>I can't say I know, but COBOL does some interesting things
>>>these days.
>>
>>COBOL has always done some 'interesting things'... have you ever dealt
>>with a hastily-implemented 66-level at 2:am? Have you ever found that
>>adding 'just one more file' creates a load module so big that it won't fit
>>into core? How about finding out the length of a variable-length record
>>by referring to... oh, folks don't do that any more, do they?
>>
>>The challenge is in making the code simple.
>
>The OP mentioned he was calling the COBOL subroutine from an
>Easytrieve.
The OP specification was 'Incidentally, I'm calling the COBOL program from
an Easytrieve program, so I'm not sure that something like address
pointers would work for me.' I interpreted this as 'merely by chance,
without minimum intention or calculation I am calling the COBOL program
from an Easytrieve program'... hence my comments focused more on the
structure of a LINKAGE SECTION than the incidents of interaction between
COBOL and Easytrieve.
If I am in error... well, wouldn't be the first time.
>I'm assuming you have multiple Easytrieves to handle the
>different size files. The only suggestion I might make since you want
>to have only 1 COBOL subroutine is to code a 32K size area in your
>COBOL and Easytrieve modules. Populate the 32K area with your table
>and send it and the "real" length to the subroutine.
>
>If your files or tables ever exceed 32k obviously you'd have to change
>it in all of the Easytrieves and the subroutine but it would be a
>simple 1 line change everywhere.
Where's your sense of imagination, man? How about... 32K worth of LINKAGE
SECTION which consists of all the program names using that particular
copybook; the first thing a CALLed program does is SEARCH for its own
name. If the name is not found you GO TO 9999-BLOW-EM-UP because the
environment is inappropriate, if the name *is* found...
... you use it as a partial key to read a VSAM KSDS and get all the
records containing data one could hope to add over the program's
twenty-some years of service.
There... doesn't that sound big, sloppy, simple, capable of being
understood by a Corner-Office Idiot... *and* it has the built-in Blame
Button of 'regular file maintenance' ('oh, someone musta forgot to update
the program's entry in the LNKSTUFF file') so nobody's ever really at
fault when this stack o' kludges falls apart regularly!
It runs right just often enough to make proper design and re-coding a real
nuisance... and has a built-in reliance on a human flaw (keeping up with
routine file maintenance) that insures there'll always be Budget allocated
for it... and getting Budget allocated is what it is all about, neh?
(32K of 8-character program names is 4,000 programs... and any
modification to any single one has to be propogated across... oh, at least
half of them, for Consistency's Sake... and that means both enough money
to keep the necessary parts of the system more-or-less working *and*
enough left over to be re-allocated into the Senior Managerial Offsite
Co-Ordinatory Functional Sessions at a golf-course)
DD
For example, if there are two fields in the record, one of which is 10
bytes long and the other is 20:
CALL subtroutine using W-FLD-10 +
'10' +
W-FLD-10-TABLE
This will be followed in the Easytrieve by the second call:
CALL subtroutine using W-FLD-20 +
'20' +
W-FLD-20-TABLE
The two tables would look like this (in COBOL):
05 W-FLD-10-TABLE PIC X(750).
05 FILLER REDEFINES W-FLD-10-TABLE OCCURS 50 TIMES.
10 W-FLD-10-VALUE PIC X(10).
10 W-FLD-10-TALLY PIC S9(09)V COMP-3.
05 W-FLD-20-TABLE PIC X(1250).
05 FILLER REDEFINES W-FLD-20-TABLE OCCURS 50 TIMES.
10 W-FLD-20-VALUE PIC X(20).
10 W-FLD-20-TALLY PIC S9(09)V COMP-3.
The Easytrieve code is created dynamically, each time a new copybook
and file are passed to it. Easytrieve is basically compile-and-go, and
while it's possible to do that with COBOL, it's not the standard in my
shop, therefore not the way I want to go with this. I was looking for
a way to code the Linkage Section of the subroutine program that could
also be dynamic without recompiling, but I think the only way I can
truly do this is to use reference modification.
I also considered some sort of VSAM setup, but my jobs have time
contstraints and the files can be very large (300-million plus).
Multiple VSAM reads for each one of those fields, also for each
record, would make for some daunting overhead.
Again, thanks for the suggestions, and if anyone has a "clean" way to
set this up so it's truly reusable (without recompiling), please let
me know.
John
>I thought about sending it through as just one big area, then chopping
>it up as needed, based on the record length (reference modification,
>etc.). I won't know my maximum from one file to the next, though -- if
>I end up with a definition in the subroutine program that's not big
>enough for what's handed down to it, is there any way I can
>dynamically point beyond the end of what's defined in my Linkage
>Section? I can't say I know, but COBOL does some interesting things
>these days.
If this could be a problem, it might be better to use files to pass
data.
"I'm not sure I made myself clear.....". You are dead right, hopping and
skipping between the task itself and some of your out of sync ideas.
Wish I was young again; could make a fortune setting up a school,
"English as a Second Language".
For starters I don't know the first thing about Easytrieve and I ain't a
mainframe Johnny.
How do you define the task? "I have a series of Easytrieve files/tables
containing records which have values, there being from one to a MAXIMUM
of 50 row/columns per record. (The "50" is from what you have written).
The Easytrieve fields can contain positive/negative values from 1 to 20
characters; (again you have specified pic x(20) below). I want a
sub-program to read in these varying values and fields and field lengths
so that I can accumulate/compare values, per column/row and store a
result" - Is that reasonably close to what you are really trying to tell
us ?
First comment - why below express a value as :-
> 10 W-FLD-10-TALLY PIC S9(09)V COMP-3.
The 'V' after (09) doesn't do a damned thing for you - your format
automatically defines an integer. And what is 'TALLY' - perhaps the
converted COBOL value for what's in the Easytrieve field :-
> 10 W-FLD-10-VALUE PIC X(10).
Why the two tables 10-TABLE and 20-TABLE ?
> 05 W-FLD-10-TABLE PIC X(750).
> 05 FILLER REDEFINES W-FLD-10-TABLE OCCURS 50 TIMES.
> 10 W-FLD-10-VALUE PIC X(10).
> 10 W-FLD-10-TALLY PIC S9(09)V COMP-3.
>
> 05 W-FLD-20-TABLE PIC X(1250).
> 05 FILLER REDEFINES W-FLD-20-TABLE OCCURS 50 TIMES.
> 10 W-FLD-20-VALUE PIC X(20).
> 10 W-FLD-20-TALLY PIC S9(09)V COMP-3.
>
It can be simplified - I can't see any necessity to have TABLE-10 and
TABLE-20.
Assuming at this point I've got a handle on what you are trying to do :-
1. Program(s) with the ability to read Easytieve records, either one per
record format or use SECTIONS to perform on different record formats.
Take the Easytrieve records and move their 'character' (??) values to a
COBOL Table, firstly having initialized TableCount to zero and
incrementing it as you move each value field :-
01 COBOL-TABLE.
05 TableCount pic 9(04) comp-3.
05 Table-Value pic x(20) occurs 1 to 50 depending upon TableCount .
Actually you are in trouble if you have pic x(20) - your COBOL only
allows for pic 9(18) - and I don't think you are doing this exercise for
Mugabe's Bank of Tanzania ! So let's go with Table-Value pic x(10)
including a positive/negative sign, if that's appropriate.
2. Call your sub-program :-
CALL SUB-PROGRAM using COBOL-TABLE
Note we are only making ONE CALL per Eastytrieve record. Don't CANCEL
the sub-program between CALLs - use EXIT PROGRAM instead. Only use
CANCEL PROGRAM when you have finished the run.
3. SUB-PROGRAM
LINKAGE :
01 Lnk-COBOL-TABLE.
05 Lnk-TableCount pic 9(04) comp-3.
05 Lnk-Table value pic x(10) occurs 1 to 50 depending upon TableCount
We aren't worrying about length of value fields - we have it fixed. It
is only your sub-program which is concerned with the 'size exercise'.
You use a PERFORM against the pic x(10), to ignore any spaces and put
the numeric value in a SEPARATE table for values in the Sub-Program :-
01 SUB-TABLE.
05 SUB-TableCount pic 9(04) comp-3.
05 Sub-Value pic s9(10) comp-3.
occurs 1 to 50 depending upon Sub-TableCount.
Again Sub-TableCount is initialized to zero for each call to the
sub-program and incremented for each value placed in the table. Now
going though your Sub-Table, using subscripting, you can compare, add,
subtract, mean, average or any other mathematical function that you want
to do. From your results pass them back through LINKAGE or call other
programs from the sub-program. (If it is a requirement, you could pass
the SUB-TABLE back through LINKAGE to the CALLing program).
Is the above close to what you ACTUALLY want to do ?
If you are worried about the re-compiling, then you have got to come up
with a more realistic number than 'OCCURS 50' which is what you keep on
indicating. It that a wild guess or from some Easytrieve analysis have
you determined that there will NEVER be more than 50 entries. Reminds me
of that 007 movie 'Never say Never...."
Jimmy, Calgary AB
Here's how I'd do it:
BEGIN
DECLARE CURSOR col_crsr IS
SELECT table_name, column_name from all_tab_cols
where owner = 'OppThumb';
FOR :table_name, :column_name IN col_csr LOOP
DELETE FROM statistics WHERE table_name = :table_name
INSERT INTO statistics
SELECT :table_name as table_name, column_name, count(*) from :table_name
GROUP BY :column_name
ORDER BY count(*) desc
WHERE rownum <= 50;
END LOOP;
If data is not in a database, configure an ODBC driver.
If you use:
LINKAGE SECTION.
01 PASSED-RECORD.
05 PASSED-LENGTH PIC 9(4) COMP.
05 PASSED-DATA PIC X(32000).
You're good to go.
Remember, LINKAGE SECTION takes up no room in the computer; the passed
parameters are merely addresses. In other words, PASSED-DATA above is not
really a big hunk of memory, but only an address to the start of the
parameter in the calling program.
Of course if PASSED-DATA in the calling program is only 1000 bytes, you must
be sure that you don't exceed 1000 bytes in the subroutine.
ANY LENGTH was created, in the 2002 Standard, for just this case. Micro Focus has it in V4
and above. I realize that doesn't help on IBM mainframe.
> LINKAGE SECTION.
> 01 PASSED-RECORD.
> 05 PASSED-LENGTH PIC 9(4) COMP.
> 05 PASSED-DATA PIC X(32000).
or if you're really fussy about mapping the correct length you could: -
05 passed_data.
07 passed_bytes pic x(1) occurs 0 to 65535 depending on
passed_length.
or get really smart and pass the string BY DESCRIPTOR then map the
descriptor in your linkage section and then copy the string (via the
descriptor) to you local variable.
Cheers Richard Maher
"HeyBub" <hey...@NOSPAMgmail.com> wrote in message
news:KI-dnRueZr_JTVLV...@earthlink.com...
Right. Some compilers, I've been told, limit a WS element to 32,000 bytes,
some to 65,000. Your milage may vary.
I think that should read, "some *older* compilers......"
Actually I think the only compilers I recall with limits are IBM OS/VS
cobol to 64K (compiler was sunsetted, when? Maybe 1996 or so?), and anything
for MS-DOS, which had a 64K (linear) addressability limit anyway so the
compilers had to follow suit.
MCM
John,
I was just a little bit testy with my previous message, but see closing
comments in this message.
So you are using an Easytrieve program to extract record data
which calls a COBOL sub-routine. From a cursory look at the Easytrieve
on-line manual I see there are permutations for fixed, variable and
undefined length etc. Regardless of individual record formats can you
determine the length of each Easytrieve field ? I'm sure there has to be
a way.
One klutzy way of doing it would be (in Easytrieve) - (a) You have your
variable value fields and a temporary field which is FIXED length
that you determine - say 6 chars in this example.
Field-1 value 123456
Field-2 value 12345678
Temp-Field = 6 chars
move Field-1 to Temp-Field
if Temp-Field <> Field-1
(i.e. Field-1<123456> and TempField <123456>
Exception Error - None
move Field-2 to TempField
if TempField <> Field-2
(i.e. Field-2 <12345678> and Temp-Field <345678>
Exception Error - assuming Easytrieve doesn't do an expansion of
Temp-Field you should get a truncation of the value as you would when
MOVing a COBOL pic x(??).
Anyway try and establish both the MAXIMUM number of rows and the MAXIMUM
length for any field value. I suggested a length of 10 because that
gives you $999 million - could be you might be in banking or investment,
so perhaps your numbers can be larger - but remember COBOL only allows a
maximum of pic 9(18).
If you get your act together ( :-) ) then you send the following table
to COBOL (shown in Linkage), via the CALL :-
CALL COBOL-program using COBOL-TABLE.
*>-------------------------------------
Program-id. COBOL-SubProgram.
WORKING-STORAGE SECTION.
01 n pic 9(04).
01 Average-Result pic s9(15) comp-3 ?????
01 Grand-Total pic s9(15) comp-3 ?????
01 Sub-Table.
05 Sub-TableCount pic 9(04) comp-3.
05 Sub-Values.
10 Sub-Value pic s9(10)comp-3 occurs 1 to 50 depending on
Sub-TableCount.
LINKAGE SECTION.
01 Lnk-Table.
05 Lnk-TableCount pic 9(04) comp-3.
05 Lnk-Values.
10 Lnk-Value pic x(10) occurs 1 to 50 depending on
Lnk-TableCount.
PROCEDURE DIVISION.
perform INITIALIZE-WORKING-TABLE
perform TRANSLATE-LINK-DATA
perform ADD-VALUES
perform AVERAGE-RESULT
perform Something-Else etc....
perform STORE-RESULTS
EXIT PROGRAM.
*> Note before I said 'EXIT PROGRAM'; only use the CANCEL when finished
ADD-VALUES.
Move zeroes to GrandTotal
Perform varying n from 1 by 1 until n > Sub-Tablecount
add Sub-Value (n) to GrandTotal
End-Perform.
*> Now as a much slicker alternative to the mundane above, providing the
*> SUM function will work with a 'set of arguments' from the
*> Sub-TableCount
compute GrandTotal = function Sum (Sub-Values)
*> Can't compile at the moment so don't know if above will work.
.
AVERAGE-RESULT.
compute Average-Result ROUNDED = GrandTotal / Sub-TableCount.
*> ROUNDED, rounds off the last digit; you still get an integer result.
*> If you had decimalised numbers the ROUNDING occurs on the last digit
of the decimal part as necessary.
.
INITIALIZE-WORKING-TABLE
move 50 to Sub-TableCount
initialize Sub-Values
*> that means all 50 - not totally necessary in this instance as your
*> Sub-TableCount should give you a run error if you try and access
*> Sub-Value (23) when your Sub-TableCount = 20. More to the point,
*> you've got a 'clean' table and shouldn't get any 'gotchas'
*> Now move the 'real' count to Sub-Table
move Lnk-Tablecount to Sub-TableCount
.
STORE-RESULTS.
*> Obviously, (well at least probably), you want the Sub-Program to CALL
Easytrieve to populate records in a Results-File table, after you have
performed each set of calculations, so that you can print an Easytrieve
Report.
TRANSLATE-LINK-DATA.
Perform varying n from 1 by 1 until n > Lnk-TableCount
compute Sub-Value (n) = function NumVal (Lnk-Value(n) )
End-Perform
.
*> Check out the Intrinsic functions - Numval-C handles values with
*> commas.
.
*>------------------------ end of sample --------------------------
I've written above freehand because I can't get at my compiler editor;
but I think it's pretty close to what you need in COBOL. Just add
paragraphs for any other stuff you are doing.
I've cheated a bit; I didn't move the Linkage Table to Working Storage;
re-read Jerry's message (Heybub) - Linkage 'points' to where it came
from. Traditionally folks move Linkage items to Working Storage - but
it's not always necessary as in this example. However "IF" and its a
real big 'If' what you might possibly change in the Linkage Section
could affect the original record, (from the CALLER) and you subsequently
do a file update in the CALLer - your data file could finish up in a
real mess.
COMMENTS :
- It's not a put down, but I get the impression you maybe quite new to
COBOL and probably don't know Easytrieve too well either. I got the
impression you were floundering a bit because you weren't getting any
advice from your own site. And it's the lack of help from your site that
irritates me.
- With the large files you have indicated your IT operation is not just
you and the cleaner ! There's probably 10 or more of you and you should
have a mentor or be able to ask one of the senior guys for
help/guidance. If one of the so-called experienced guys blusters with a
"You should be able to work that out on your own" - tells me he probably
doesn't know too much more than you do while he has been raking in the
money under false pretenses.
Alternatively, you might get a "Go away and do it yourself". Write
either or both of them off, and enter in your notebook 'Jack Jones -
asshole'. Unfortunately you will meet a few more of 'em before you retire.
- On another thought - are you embarrassed to ask your locals ? That's
professional suicide. We all had to start in COBOL from scratch, so you
are just one of the latest in-line. Never be afraid to ask and let the
other person know that you don't know - it pays off in the end. You have
Easytrieve available, read up on it and try examples until you become
proficient - it makes another skill on your CV - and it's concepts
aren't that far removed from DBMS SQL systems, which you should be able
to adjust to as the need becomes necessary.
From what you wrote at least one file has 'Undefined Record Length'.
Now the guy who originally set up the table, or his successor did it to
produce specific reports. If 'X' is long gone get a hold of an
Easytrieve source where a report is produced from Undefined Record
Length - bearing in mind if you are laying out report line formats you
just GOTTA know how many characters you can fit per line.
Unless you were specifically told by the Chief Programmer or your Team
Leader to "Do this in COBOL", I've a gut feeling it can probably all be
done in Easytrieve, with the proviso, that when googling I saw a
statement which said something like, "Easytrieve doesn't have all the
mathematical features of COBOL", (which might be an indirect reference
to Intrinsic Functions that I've used above).
...... Anyway, hope the dummy program helps a bit.
Jimmy, Calgary AB