Variable Length Records
Variable Length Records
One-to-many relationships are common in business systems. For example, one sales rep
can have many customers, one customer can have many invoices, one invoice can have
many items, etc. In modern systems, these relationships would likely be implemented
with a relational database system using joins of multiple tables. In legacy systems, such
relationships were commonly implemented in a hierarchical database or, more simply,
with variable length records. This article will focus on how variable length records are
stored internally.
To illustrate, consider the following credit card example. Let's assume one person can
have many credit cards, but each credit card belongs to one and only one person. Since
each record will have a variable number of credit cards, the record will typically include a
field which indicates how many. We will choose an arbitrary maximum of 3 credit cards
per person (artifically low to simplify our example.) The fixed portion of each record will
contain an ID number (3 bytes), first name (10 bytes), last name (10 bytes), and
occurances count (2 bytes), for a total of 25 bytes. For each credit card we will store the
credit card number (4 bytes), credit card type (4 bytes) and balance due (4 bytes), for a
total of 12 bytes. So each record contains from 25 bytes to 61 bytes (25 + (3*12)).
When the system stores a variable length record, it puts a four byte record descriptor
word (RDW) on the front of each record. This RDW is not always visible (such as within
a COBOL program) but it's there. The first two bytes of the RDW is a binary halfword
(PIC S9(4) COMP) containing the length of the record. This length includes the data and
the RDW itself. Consequently, our RDW will have a value of 29 to 65. This highest
number (65) will be the LRECL when we allocate the file. The second two bytes of the
RDW contains X'0000'.
We can allocate a simple variable length file with ISPF panel 3.2. For example:
______________________________________________________________________________
Allocate New Data Set
Command ===>
______________________________________________________________________________
Edit Entry Panel
Command ===>
ISPF Library:
Project . . . U0290
Group . . . . ISPF . . . . . . . . .
Type . . . . CNTL
Member . . . (Blank or pattern for member selection list)
Workstation File:
File Name . . . . .
Options
Initial Macro . . . . Confirm Cancel/Move/Replace
Profile Name . . . . . Mixed Mode
Format Name . . . . . Edit on Workstation
Data Set Password . . / Preserve VB record length
We can enter the data as follows. Note that although the LRECL is 65, the ruler (from the
COLS command) only goes out to column 61. The difference is the RDW (4 bytes)
which is not seen.
_______________________________________________________________________________
EDIT U0290.CREDIT.CARDS Columns 00001 00061
Command ===> Scroll ===> HALF
****** ***************************** Top of Data
******************************
=COLS> ----+----1----+----2----+----3----+----4----+----5----+----6-
000001 987BILL QUALLS 035555VISA10002345MAST05001234DISC0100
000002 123RUBECCA ALINIAZEE 011010VISA0000
000003 786ERIC ALBERT 022323MAST01003434DISC9999
000004 432JASON ROGERS 017777DISC0750
****** **************************** Bottom of Data
****************************
IDCAMS can be used to dump the file. The JCL appears as follow:
_______________________________________________________________________________
EDIT U0290.ISPF.CNTL(DUMPVB) - 01.00 Columns 00001 00072
Command ===> Scroll ===> HALF
****** ***************************** Top of Data
******************************
000001 //U0290DMP JOB (PRM,0,T),'BILL QUALLS',
000002 // CLASS=A,MSGCLASS=T,TIME=(0,59),NOTIFY=U0290
000003 //STEP010 EXEC PGM=IDCAMS
000004 //MYINPUT DD DSN=U0290.CREDIT.CARDS,DISP=SHR
000005 //SYSIN DD *
000006 PRINT INFILE(MYINPUT) DUMP
000007 //SYSPRINT DD SYSOUT=*
****** **************************** Bottom of Data
****************************
We can see from the following dump that the records are, in fact, varying in length.
_______________________________________________________________________________
EDIT U0290.ISPF.CNTL(DUMPVB) - 01.00 Columns 00001 00072
Command ===> Scroll ===> HALF
****** ***************************** Top of Data
******************************
000001 //U0290DMP JOB (PRM,0,T),'BILL QUALLS',
000002 // CLASS=A,MSGCLASS=T,TIME=(0,59),NOTIFY=U0290
000003 //STEP010 EXEC PGM=IDCAMS
000004 //MYINPUT DD DSN=U0290.CREDIT.CARDS,DISP=SHR,DCB=RECFM=U
000005 //SYSIN DD *
000006 PRINT INFILE(MYINPUT) DUMP
000007 //SYSPRINT DD SYSOUT=*
****** **************************** Bottom of Data
****************************
The resulting dump is at the same time confusing and revealing:
Look at the first line and you will see 00410000. This is the RDW for the first record.
X'0041' is the hexadecimal representation of the number 65 (4 * 16 + 1). This is the total
length of the first record. Find 00290000 in the third line. This is the RDW for the second
record: 29 base 16 = 41 base 10. Similarly, you will see 00350000 in the fourth line and
00290000 in the sixth line, representing the lengths of the third (53) and fourth (41)
records respectively.
Just as an RDW describes each record, a BDW describes each block. Find 00CC0000 in
the first line. CC base 16 = 204 base 10. This is the length of the block: 65 (first) + 41
(second) + 53 (third) + 41 (fourth) + 4 (for the BDW itself.)