Variable Length Records 
Author Message
 Variable Length Records

I need to create variable length records from a mainframe (MVS) PL1
program. I am reading in CHAR fields such as names and other variable
values and need to create a comma delimited file.

I cannot get the program to write out anything but a fixed length
record, despite setting up the output file as VB and adding four bytes
to the longest possible record length.

I have tried an outpout structure made up of several varying fields,
e.g.

DCL   1  Output_Structure,
        2 Surname CHAR(25) Varying,
        2 Comma1 CHAR(1) Init(','),
        2 Forename CHAR(25) Varying,
        2 Comma2 CHAR(1) Init (','),

        etc.

But when I test the program using a debugging tool, Surname has a
length of 25, even if the vlaue is only 12 characters long.

Another problem occurs when I try to write out the record, when I get
an ONCODE 22 error. This seems to be something to do with a mismatch
between the output structure and the actual file length.

I have even tried to concatenate the individual values into a single
string and write the record from there, but this suffers from the same
problem.

Has anyone done this sort of thing before and can you help?




Tue, 17 Aug 1999 03:00:00 GMT  
 Variable Length Records

Quote:

> I need to create variable length records from a mainframe (MVS) PL1
> program.

> DCL   1  Output_Structure,
>         2 Surname CHAR(25) Varying,
>         2 Comma1 CHAR(1) Init(','),
>         2 Forename CHAR(25) Varying,

> But when I test the program using a debugging tool, Surname has a
> length of 25, even if the vlaue is only 12 characters long.

> I have even tried to concatenate the individual values into a single
> string and write the record from there, but this suffers from the same
> problem.

Your structure will never work; without a REFER the whole structure will
be put out, including length fields and slack bytes.  Concatenating
strings
should have worked, however; I used to do this frequently.  Perhaps you
are
failing to trim trailing blanks from the fields you read in?  Something
like
this should work:

  DCL outfile FILE RECORD OUTPUT ENV(BLKSIZE(260) RECSIZE(256) VB);
  DCL outrec CHAR(252) VAR;

  outrec = "Surname";
  outrec = outrec || ", ";
  outrec = "Name";

  WRITE FILE(outfile) FROM(outrec);

I don't know which PL/I you are using; you probably don't have a TRIM()
function on MVS, but something like this would do the trick:

  len = LENGTH(outrec);
  DO i = LENGTH(outrec) TO 1 BY -1 WHILE( SUBSTR(outrec,i,1) = " ");
    len = len - 1;
  END;
  outrec = SUBSTR(outrec, 1, len);

Obviously there are more efficient ways to trim blanks using builtin
functions.

If all this doesn't make it clear to you, try posting a simplified
version of
your code.



Tue, 17 Aug 1999 03:00:00 GMT  
 Variable Length Records


Length Records

b>I have tried an outpout structure made up of several varying fields,
b>e.g.

b>DCL   1  Output_Structure,
b> 2 Surname CHAR(25) Varying,
b> 2 Comma1 CHAR(1) Init(','),
b> 2 Forename CHAR(25) Varying,
b> 2 Comma2 CHAR(1) Init (','),

[snip]
b>Has anyone done this sort of thing before and can you help?

This is fairly straightforward when you switch from move mode to locate mode
I/O.

To exploit varying length records like this you need to split the CHAR VAR
fields into their piece parts: a half-word integer and a character field.
The structure needs to be based on a pointer rather than discretely
allocated in automatic storage. E.g.

     DCL  Output_structure_ptr  PTR,
          1  Output_structure   BASED(Output_structure_ptr),
             2 Surname_len      BIN FIXED(15,0),
             2 Surname          CHAR((LENGTH(Surname_in))
                                REFER (Surname_len))
                                INIT((Surname_in)),
             2 Comma1           CHAR(1) INIT(','),
             2 Forename_len     BIN FIXED(15,0),
             2 Forename         CHAR((LENGTH(Forename_in))
                                REFER (Forename_len))
                                INIT((Forename_in)),
             2 Comma2           CHAR(1) INIT(',');

The above assumes you have the names in CHAR VAR fields called Forename_in
and Surname_in. To write a record you simply code the line:

     LOCATE Output_structure FILE(OUTFILE);

The INIT specifications are performed dynamically by the LOCATE statement.
The two integer fields are filled implicitly by the REFER options.

To read these back you use the same declaration [omit the INIT options if
you don't have Forename_in and Surname_in being used], possibly renamed to
Input_structure for clarity, and code:

     READ FILE(INFILE) SET(Input_structure_ptr);

As an interesting exercise, you might care to consider the STRING() built-in
function. This will "ravel" all the string-like elements of a structure into
a single string. To exploit this, and perhaps gain some miniscule
performance benefits, you could reorder the fields in the input and output
structures as follows:

     DCL  Input_structure_ptr   PTR,
          1  Input_structure    BASED(Input_structure_ptr),
             2 Surname_len      BIN FIXED(15,0),
             2 Forename_len     BIN FIXED(15,0),
             2 Name_structure,
               3 Surname          CHAR((25) REFER (Surname_len)),
               3 Comma1           CHAR(1),
               3 Forename         CHAR((25) REFER (Forename_len)),
               3 Comma2           CHAR(1);

Under this approach the neat, simple expression STRING(Name_structure) will
be the fully concatenated personal name, with commas. I'll leave it to you
to figure where the miniscule performance gain might reside -- and on modern
CPU's it really is miniscule.

[If Peter and/or Carolyn are lurking at Santa Teresa labs: I think this
topic (based structures and locate mode I/O) could be expanded into a
worthwhile little article for "The PL/I Connection".]

Regards

Dave
<Team PL/I>
___
 * MR/2 2.25 #353 * Chicago -- Microsoft's "New Coke"



Wed, 18 Aug 1999 03:00:00 GMT  
 Variable Length Records

Quote:

> I need to create variable length records from a mainframe (MVS) PL1
> program. I am reading in CHAR fields such as names and other variable
> values and need to create a comma delimited file.

> I have tried an outpout structure made up of several varying fields,
> e.g.

> DCL   1  Output_Structure,
>         2 Surname CHAR(25) Varying,
>         2 Comma1 CHAR(1) Init(','),
>         2 Forename CHAR(25) Varying,
>         2 Comma2 CHAR(1) Init (','),

>         etc.

> But when I test the program using a debugging tool, Surname has a
> length of 25, even if the vlaue is only 12 characters long.

This is the way I'd do it (actually, this is the way I _do_ it :-)):

1) Declare a CHAR VARYING string to hold the record. Declare it long
enough to contain the largest record you intend to write:

DCL IO_AREA             CHAR(1024) VARYING;

2) Initialize it to the 'null' string:

IO_AREA = '';

3) Fill it with PUT STRING EDIT statements:

PUT STRING(IO_AREA)
    EDIT(SURNAME,",",FORENAME,",",MOREDATA)
        (A,A,A,A,A);

4) Write the string to the file:

WRITE FILE(MYFILE) FROM(IO_AREA)

MYFILE has to be declared in your JCL with
DCB=(RECFM=VB,LRECL=1024,BLKSIZE=...)

(You could use STREAM I/O and avoid the PUT STRING stuff; I've not tried
it since my site policy is to avoid STREAM I/O).

BTW, the variables SURNAME, FORENAME and MOREDATA should be CHAR VARYING
strings with the proper length.

Greetings;

--
************************************************************/
* Jordi Guillaumes i Pons - Barcelona, Catalonia (Europe)  */

* http://ourworld.compuserve.com/homepages/jguilla         */
************************************************************/



Thu, 19 Aug 1999 03:00:00 GMT  
 Variable Length Records

In a message dated 03-02-97, Jordi Guillaumes i Pons said to All about
Variable Length Record

JP>PUT STRING(IO_AREA)
JP>    EDIT(SURNAME,",",FORENAME,",",MOREDATA)
JP>        (A,A,A,A,A);

JP>4) Write the string to the file:

JP>WRITE FILE(MYFILE) FROM(IO_AREA)

[snip]

JP>(You could use STREAM I/O and avoid the PUT STRING stuff; I've not tried
JP>it since my site policy is to avoid STREAM I/O).

This is a real gem!

You pay for all the formatting overheads of STREAM, which are unavoidable,
by using PUT STRING and then write each line individually using WRITE. This
means you have to start and stop the transmitter modules for each line of
output.

When you combine this with having to code your own logic to determine
end-of-page, it is the worst of both worlds.

This is what comes from letting non-programmers define site coding
standards.

By using STREAM directly with PUT FILE you can transfer a load of lines in
one invocation of the transmitter routine. It's actually faster than RECORD
transmission if you know what you're doing.

Regards

Dave
<Team PL/I>
___
 * MR/2 2.25 #353 * Drive A: not responding...Formatting C: instead



Thu, 19 Aug 1999 03:00:00 GMT  
 Variable Length Records


        >I need to create variable length records from a mainframe (MVS) PL1
        >program. I am reading in CHAR fields such as names and other variable
        >values and need to create a comma delimited file.

        >I cannot get the program to write out anything but a fixed length
        >record, despite setting up the output file as VB and adding four bytes
        >to the longest possible record length.

        >I have tried an outpout structure made up of several varying fields,
        >e.g.

        >DCL   1  Output_Structure,
        >    2 Surname CHAR(25) Varying,
        >    2 Comma1 CHAR(1) Init(','),
        >    2 Forename CHAR(25) Varying,
        >    2 Comma2 CHAR(1) Init (','),

        >    etc.

        >But when I test the program using a debugging tool, Surname has a
        >length of 25, even if the vlaue is only 12 characters long.

        >Another problem occurs when I try to write out the record, when I get
        >an ONCODE 22 error. This seems to be something to do with a mismatch
        >between the output structure and the actual file length.

        >I have even tried to concatenate the individual values into a single
        >string and write the record from there, but this suffers from the same
        >problem.

        >Has anyone done this sort of thing before and can you help?


I assume you're using RECORD I/O.  If so, you'll need something
like this:

DCL   1  Output_Structure BASED (User),,
        2 Length_Surname        FIXED BINARY,
        2 Length_Forename       FIXED BINARY,
        2 Surname               CHAR(25 REFER (Length_Surname)),
        2 Comma1                CHAR(1) Init(','),
        2 Forename              CHAR(25 REFER (Length_Forename)),
        2 Comma2                CHAR(1) Init (','),
DCL User POINTER;

   ...
   Allocate Output_Structure;
   Surnane = ... [actual constant or varying-length variable]
   Forename = ...
   WRITE FILE (. . . ) FROM (Output_Structure);
   Free Output_Structure;



Fri, 20 Aug 1999 03:00:00 GMT  
 Variable Length Records



        >Length Records

        >b>I have tried an outpout structure made up of several varying fields,
        >b>e.g.

        >b>DCL   1  Output_Structure,
        >b> 2 Surname CHAR(25) Varying,
        >b> 2 Comma1 CHAR(1) Init(','),
        >b> 2 Forename CHAR(25) Varying,
        >b> 2 Comma2 CHAR(1) Init (','),

        >b>Has anyone done this sort of thing before and can you help?

        >This is fairly straightforward when you switch from move mode to locate mode
        >I/O.

        >To exploit varying length records like this you need to split the CHAR VAR
        >fields into their piece parts: a half-word integer and a character field.
        >The structure needs to be based on a pointer rather than discretely
        >allocated in automatic storage. E.g.

        >     DCL  Output_structure_ptr  PTR,
        >          1  Output_structure   BASED(Output_structure_ptr),
        >             2 Surname_len      BIN FIXED(15,0),
        >             2 Surname          CHAR((LENGTH(Surname_in))
        >                                REFER (Surname_len))
        >                                INIT((Surname_in)),
        >             2 Comma1           CHAR(1) INIT(','),
        >             2 Forename_len     BIN FIXED(15,0),
        >             2 Forename         CHAR((LENGTH(Forename_in))
        >                                REFER (Forename_len))
        >                                INIT((Forename_in)),
        >             2 Comma2           CHAR(1) INIT(',');

I think you'll need the REFER fields at the beginning of the
record, before the variable parts, like you did in the
second example:

        >DCL  Input_structure BASED ( . . . ) PTR,
                1 Name_structure,
        >             2 Surname_len      BIN FIXED(15,0),
        >             2 Forename_len     BIN FIXED(15,0),
        >             2 Name_structure,
        >               3 Surname          CHAR((25) REFER (Surname_len)),
        >               3 Comma1           CHAR(1),
        >               3 Forename         CHAR((25) REFER (Forename_len)),
        >               3 Comma2           CHAR(1);



Fri, 20 Aug 1999 03:00:00 GMT  
 Variable Length Records


Quote:
>In a message dated 03-02-97, Jordi Guillaumes i Pons said to All about
>Variable Length Record

>JP>PUT STRING(IO_AREA)
>JP>    EDIT(SURNAME,",",FORENAME,",",MOREDATA)
>JP>        (A,A,A,A,A);

>JP>4) Write the string to the file:

>JP>WRITE FILE(MYFILE) FROM(IO_AREA)

>[snip]

>JP>(You could use STREAM I/O and avoid the PUT STRING stuff; I've not tried
>JP>it since my site policy is to avoid STREAM I/O).

>This is a real gem!

>You pay for all the formatting overheads of STREAM, which are unavoidable,
>by using PUT STRING and then write each line individually using WRITE. This
>means you have to start and stop the transmitter modules for each line of
>output.

>When you combine this with having to code your own logic to determine
>end-of-page, it is the worst of both worlds.

>This is what comes from letting non-programmers define site coding
>standards.

>By using STREAM directly with PUT FILE you can transfer a load of lines in
>one invocation of the transmitter routine. It's actually faster than RECORD
>transmission if you know what you're doing.

>Regards

>Dave
><Team PL/I>

Correct.  This is a very unfortunate "site policy," leading to many structures and formatting
statements in order to avoid the "inefficiency" of Stream I/O.  My favorite comment used to  
be "You will not be able to lift, let alone carry, the output I can print with five seconds of
Stream I/O!"

As to the underlying question about variable-length records.  I'm sure based with
refer is fine, but concatenating varying-length strings whose trailing blanks have
been removed sounds easiest.     Use ENV(VB RECSIZE( nnn ) ) where "nnn" is at
least four bytes larger than the longest record you expect to use, then set
BLKSIZE on the outside to a convenient large value, perhaps "half-track" blocking,
the largest value that will fit two blocks per track.   Recent versions of MVS do this
automatically if the data set is allocated with DSORG, RECFM and LRECL.

Do NOT use BLKSIZE(260) for LRECL(256).  Yes, it will work, but it will write short
blocks on the DASD tracks.  These will waste a lot of space and will cause serious
elapsed-time delays, due to taking one rotation of the disk volume for each block
read.  

In my former MVS duties I had the pleasure of showing some of our users just what it
meant to go from an unblocked (or short-blocked) to a large blocksize.   Lengthy
delays, often a minute or more, to ISPF Browse to the bottom of a large unblocked file,
compared with I/O so fast the user could hardly lift a finger off the keyboard before
the bottom of the blocked file appeared.

Bob McNeill
IBM Global Services
IBM Thomas J. Watson Research Center
Yorktown Heights, NY



Fri, 20 Aug 1999 03:00:00 GMT  
 Variable Length Records


 >The INIT specifications are performed dynamically by the LOCATE
statement.
 >The two integer fields are filled implicitly by the REFER options.
 >
 >To read these back you use the same declaration [omit the INIT options if
 >you don't have Forename_in and Surname_in being used], possibly renamed
to
 >Input_structure for clarity, and code:

Has REFER processing gotten much faster in later version of the compiler?

I can recall convincing a colleague to write a new version of his SMF
analasis program using REFER and dynamic remapping; upon trying to run this
beast, we soon determined that we'd be spending almost as much time
analyzing our SMF data as we did with our production :-/. Changing it back
to "walk" the structure cured the processing time problems.

Of course, this was back in the days of IBM's v1 optimizing compiler ...



Sat, 21 Aug 1999 03:00:00 GMT  
 Variable Length Records

On Tuesday, 97/03/04, Verne Arase wrote to All about "Variable Length
Recor" as follows:

VA> Has REFER processing gotten much faster in later version of the
VA> compiler?

I never found it to be all that slow, except when I placed the length
fields badly (such as Robin pointed out about one of my earlier
posts).

VA> I can recall convincing a colleague to write a new version of his
VA> SMF analasis program using REFER and dynamic remapping; upon trying
VA> to run this beast, we soon determined that we'd be spending almost
VA> as much time analyzing our SMF data as we did with our production
VA> :-/. Changing it back to "walk" the structure cured the processing
VA> time problems.

In that situation you are faced with living with the length
descriptors being placed where IBM decided. It is usually far from
optimal, unless you have a pointer in a register.

If you could rewrite SMF (yeah, right) it would have run quicker.
Alternatively, you could extract each record's data into a more
optimal structure up front, and then examine fields as needed from the
optimised structure.

VA> Of course, this was back in the days of IBM's v1 optimizing
VA> compiler ...

I've used worse code generators, e.g. VS COBOL I with the Capex
Optimizer.

Regards

Dave
<Team PL/I>

 * KWQ/2 1.2i * Christ died for our sins, so let's not disappoint him.
--
Please remove the '$' in the from line before reply via email.
Anti-UCE filter in operation.



Sun, 22 Aug 1999 03:00:00 GMT  
 
 [ 15 post ] 

 Relevant Pages 

1. Getting true length of a variable length record - IBM Mainframe

2. Finding Variable-Length Record Length

3. processing variable length records in text file

4. Variable Length records in VS/Cobol II rel 3.0

5. Reading variable-length records from a file

6. Memory representation of variable length record components

7. How to access files with variable length records?

8. How to access files with variable length records?

9. Write variable length records....

10. Variable Length Records

11. Attempting to read variable length records as raw data

12. Sorting a file with variable length records.

 

 
Powered by phpBB® Forum Software