Previous | Contents | Index |
An indexed sequential file must have at least one key. The first (primary) key is always numbered 0. An indexed sequential file can have up to 255 keys; however, for file-processing efficiency it is recommended that you define no more than 7 or 8 keys. (The time required to insert a new record or update an existing record is directly related to the number of keys defined; the retrieval time for an existing record, however, is unaffected by the number of keys.)
When you design an indexed sequential file, you must define each key in the following terms:
When you want to define more than one key, or to define keys of different data types, you must be careful when you specify the key fields. The next few subsections describe some considerations for specifying keys.
Specifying Key Position and Size
When you specify a key, you must specify both its position in the record and its length. The position is specified with respect to the beginning of the record; thus, a key that is positioned beginning in the first byte of the record has a starting position of 0, a key positioned beginning in the 21st byte has a key position of 20, and so on.
If the ENVIRONMENT option SCALARVARYING is in effect, the key size for a CHARACTER VARYING key should be 2 more than your declared maximum size; you specify a key position offset 2 from the variable base offset.
To determine the key positions for fields within a structure, you can examine the storage map in the program listing that defines the structure. The following structure definition illustrates the relationships between key field definitions and the storage map offsets:
1 FOO: PROCEDURE; 2 1 DECLARE 1 STATE BASED (STATE_PTR), 3 1 2 NAME CHARACTER (20), /*Primary key */ (1) 4 1 2 POPULATION FIXED BINARY(31), /*3rd alternate key */(4) 5 1 2 CAPITAL, 6 1 3 NAME CHARACTER(20), 7 1 3 POPULATION FIXED BINARY(31), 8 1 2 LARGEST_CITIES(2), 9 1 3 NAME CHARACTER(30), 10 1 3 POPULATION FIXED BINARY(31), 11 1 2 SYMBOLS, 12 1 3 FLOWER CHARACTER(30), /*1st alternate key*/ (2) 13 1 3 BIRD CHARACTER(30); /*2nd alternate key*/ (3) 14 1 15 1 END FOO; |
The resultant storage map shows the following:
The storage map is:
+-------------+ | Storage Map | +-------------+ External Entry Points and Variables Declared Outside Procedures --------------------------------------------------------------- Identifier Name Storage Size Line Attributes ---------- ---- ------- ---- ---- ---------- FOO 1 ENTRY, EXTERNAL Procedure FOO on line 1 ----------------------- Identifier Name Storage Size Line Attributes ---------- ---- ------- ---- ---- ---------- BIRD 30 BY 13 OFFSET FROM BASE IS 146 BY, MEMBER OF STRUCTURE SYMBOLS, CHARACTER(30) UNALIGNED, NONVARYING (3) CAPITAL 24 BY 5 OFFSET FROM BASE IS 24 BY, MEMBER OF STRUCTURE STATE, STRUCTURE FLOWER 30 BY 12 OFFSET FROM BASE IS 116 BY, MEMBER OF STRUCTURE SYMBOLS, CHARACTER(30) UNALIGNED, NONVARYING (2) LARGEST_CITIES 68 BY 8 OFFSET FROM BASE IS 48 BY, MEMBER OF STRUCTURE STATE, STRUCTURE DIMENSION NAME 30 BY 9 OFFSET FROM BASE IS 48 BY, MEMBER OF STRUCTURE LARGEST_CITIES CHARACTER(30), UNALIGNED, NONVARYING NAME 20 BY 6 OFFSET FROM BASE IS 24 BY, MEMBER OF STRUCTURE CAPITAL, CHARACTER(20) UNALIGNED, NONVARYING NAME 20 BY 3 OFFSET FROM BASE IS 0 BY, MEMBER OF STRUCTURE STATE, CHARACTER(20) UNALIGNED, NONVARYING (1) POPULATION 4 BY 10 OFFSET FROM BASE IS 78 BY, MEMBER OF STRUCTURE LARGEST_CITIES FIXED BIN(31,0), ALIGNED, PRECISION POPULATION 4 BY 7 OFFSET FROM BASE IS 44 BY, MEMBER OF STRUCTURE CAPITAL, FIXED BIN(31,0) ALIGNED, PRECISION POPULATION 4 BY 4 OFFSET FROM BASE IS 20 BY, MEMBER OF STRUCTURE STATE, FIXED BIN(31,0) ALIGNED, PRECISION (4) STATE based 176 BY 2 STRUCTURE SYMBOLS 60 BY 11 OFFSET FROM BASE IS 116 BY, MEMBER OF STRUCTURE STATE, STRUCTURE . . . |
After you enter the EDIT/FDL command, you can specify the keys to FDL as follows:
Enter Desired Primary (Keyword)[-] : KEY 0 - Legal KEY 0 Secondary Attributes - CHANGES yes/no LEVEL1_INDEX_AREA number DATA_AREA number NAME string DATA_FILL number NULL_KEY yes/no DATA_KEY_COMPRESSION yes/no NULL_VALUE char/num DATA_RECORD_COMPRESSION yes/no POSITION number DUPLICATES yes/no PROLOGUE number INDEX_AREA number TYPE keyword INDEX_COMPRESSION yes/no SEGn_LENGTH number INDEX_FILL number SEGn_POSITION number LENGTH number Enter KEY 0 Attribute (Keyword)[-] :POSITION[Return] KEY 0 SEG0_POSITION Enter value for this Secondary (0-16299)[-] :0[Return] - Resulting Primary Section - KEY 0 SEG0_POSITION 0 Continue with this Same Primary (Yes/No)[No] :YES[Return] |
At this point, the menu Secondary Attributes reappears on your screen:
Enter KEY 0 Attribute (Keyword)[-] :LENGTH[Return] KEY 0 SEG0_LENGTH Enter value for this Secondary (0-255)[-] :20[Return] - Resulting Primary Section - KEY 0 SEG0_LENGTH 20 SEG0_POSITION 0 Continue with this Same Primary (Yes/No)[No] :[Return] |
At this point, you return to the first menu. To establish the keys necessary for ADDRESS.DAT, you need to step through the entire process again. In response to the prompt after the first menu, type ADD; in response to the prompt after the second menu, type KEY 1. Give KEY 1 (for example) a position of 116 and a length of 30.
Establish the third and last key the same way. Give KEY 2 a position of 146 and a length of 30. Then go back to the first menu and type VIEW in response to the prompt. A summary appears as follows:
KEY 0 SEG0_LENGTH 20 SEG0_POSITION 0 KEY 1 SEG0_LENGTH 30 SEG0_POSITION 116 KEY 2 SEG0_LENGTH 30 SEG0_POSITION 146 |
Use FDL to change information if necessary.
Table 6-2 summarizes the valid data types for keys in RMS indexed sequential files, lists the corresponding PL/I data type declaration, and shows how to specify the key data type and length to the FDL Facility.
Data Type |
PL/I Declaration |
FDL Specification |
---|---|---|
String 1 |
CHAR(n), where
1 < n < 255 |
STR
n |
15-bit signed
integer |
FIXED BINARY(15) |
INT
2 |
31-bit signed
integer |
FIXED BINARY(31) |
INT
4 |
63-bit signed
integer |
FIXED BINARY(63) |
INT
8 |
16-bit unsigned
binary 2 |
FIXED BINARY(15) |
BIN
2 |
32-bit unsigned
binary 2 |
FIXED BINARY(31) |
BIN
4 |
64-bit unsigned
binary 2 |
FIXED BINARY(64) |
BIN
8 |
Packed decimal |
FIXED DECIMAL(n)
where 1 < n < 16 |
DECIMAL
n |
When you define the keys in an indexed sequential file, you must assign an index number to each alternate key. The index number of the primary key is always 0; subsequent alternate key indexes are numbered 1, 2, and so on. When you create a file with the FDL Facility, you must define the keys in index number order.
When you want to access a record in an indexed sequential file by an alternate key, you specify the index number. You can specify the index number either in the INDEX_NUMBER option of ENVIRONMENT or in the INDEX_NUMBER option of a record I/O statement.
For example, to access the record for a state whose flower is MAGNOLIA in the indexed file STATE_FILE, when the current index is not 1, you must specify the index number 1, as in the following example:
READ FILE(STATE_FILE) INTO(STATE) KEY('MAGNOLIA') OPTIONS(INDEX_NUMBER(1)); |
When you define alternate indexes for an indexed sequential file, you can specify the following information:
These options are described in the OpenVMS File Definition Language Facility Reference Manual.
6.7.4 Using Indexed Sequential Files
After you have defined and created an indexed sequential file, you can write records to it by opening it with the UPDATE attribute and using PL/I WRITE statements. For example:
OPEN FILE(STATE_FILE) RECORD DIRECT UPDATE; . . . WRITE FILE(STATE_FILE) FROM(STATE) KEYFROM(STATE.NAME); |
This WRITE statement writes the record whose key value is specified by the field STATE.NAME in the structure STATE.
When a WRITE statement adds a record to an indexed sequential file, the value of the KEYFROM option must always be the primary key. In fact, the WRITE statement causes the index number to be reset to zero if any other index number is in effect.
When PL/I copies the KEYFROM value into the record, it overwrites anything already in those positions, while distributing segmented values as specified by the RMS key description. Therefore, it is important that the key value come from some variable other than the record variable itself. |
Populating an Indexed Sequential File
There are two techniques for optimizing the initial population (loading) of an indexed sequential file:
For details on specifying fill numbers for the FDL Facility, see the OpenVMS File Definition Language Facility Reference Manual.
Reading an Indexed Sequential File Sequentially
To read records in an indexed sequential file in collating order by key value, open the file with the INPUT and SEQUENTIAL attributes. The following example illustrates reading the file STATE_FILE in sequential order using the primary key, that is, using the STATE.NAME field. This procedure uses the SET option of the READ statement; thus, no space is required in the records.
DECLARE STATE_PTR POINTER, STATE_FILE FILE, EOF BIT(1) INITIAL ('0'B); DECLARE 1 STATE BASED (STATE_PTR), 2 NAME CHARACTER(20), . . . ON ENDFILE(STATE_FILE) EOF = '1'B; OPEN FILE(STATE_FILE) INPUT SEQUENTIAL; READ FILE(STATE_FILE) SET(STATE_PTR); DO WHILE (^EOF); PUT SKIP(2) LIST('State:',STATE.NAME); PUT SKIP(2) EDIT('Population:',STATE.POPULATION) (A,P'ZZ,ZZZ,ZZZ'); . . . READ FILE(STATE_FILE) SET(STATE_PTR); END; |
Accessing Records by Alternate Key
To use an alternate key to read a record in an indexed sequential file, specify the INDEX_NUMBER option on the READ statement.
For example, if a file containing data about states has as its primary key the state name, it might have alternate keys for state flowers, birds, and so on. Assuming that a field called FLOWER is the first alternate key, you could access the record for a state whose flower is MAGNOLIA by writing the following statements:
OPEN FILE(STATE_FILE) KEYED INPUT; READ FILE(STATE_FILE) SET(STATE_PTR) KEY('MAGNOLIA') OPTIONS(INDEX_NUMBER(1)); |
The INDEX_NUMBER option followed by 1 specifies the first alternate index, the FLOWER field. The INDEX_NUMBER option is also valid on the REWRITE and DELETE statements.
You can access a file starting with an alternate index by opening the file with the INDEX_NUMBER option of the ENVIRONMENT attribute as in the following example:
OPEN FILE(STATE_FILE) SEQUENTIAL INPUT ENV( INDEX_NUMBER(2)); READ FILE(STATE_FILE) SET(STATE_PTR); DO WHILE (^EOF); PUT SKIP EDIT(STATE.BIRD,'is the bird of',STATE.NAME) (A,X,A,X,A); READ FILE(STATE_FILE) SET(STATE_PTR); END; |
Updating Records in an Indexed Sequential File
You can modify records in an indexed sequential file by opening the file with the UPDATE attribute, and using the REWRITE and DELETE statements to modify or delete records from the file.
The following example shows the correction of an invalid field in a record in the file STATE_FILE:
DECLARE (STATENAME,NEWFLOWER) CHARACTER(30) VARYING; . . . OPEN FILE(STATE_FILE) KEYED SEQUENTIAL UPDATE; GET SKIP LIST(STATENAME) OPTIONS (PROMPT('State: ')); READ FILE(STATE_FILE) SET(STATE_PTR) KEY(STATENAME); GET SKIP LIST(NEWFLOWER) OPTIONS( PROMPT('New state flower name: ')); STATE.FLOWER = NEWFLOWER; REWRITE FILE(STATE_FILE); |
Specifying the Type of Key Match
RMS allows generic key matching; that is, it can locate a record in an indexed sequential file whose key is greater than a specified key value, or whose key is greater than or equal to a specified key value. In PL/I, you can access records by generic key using the MATCH_NEXT and MATCH_NEXT_EQUAL options on a record I/O statement.
For example, the file STATE_FILE's third alternate key is the state's population. To list all states whose populations are greater than a specified size, you could open and read the file as follows:
DECLARE EOF BIT(1) STATIC INIT('0'B), SIZE FIXED BIN(31); OPEN FILE(STATE_FILE) KEYED SEQUENTIAL ENV( INDEX_NUMBER(3)); GET LIST(SIZE) OPTIONS(PROMPT('Starting population: ')); READ FILE(STATE_FILE) SET (STATE_PTR) KEY(SIZE) OPTIONS(MATCH_NEXT_EQUAL); DO WHILE (^EOF); PUT SKIP EDIT(STATE.NAME,'Population is ', STATE.POPULATION) (A,A,P'ZZ,ZZZ,ZZZ'); READ FILE(STATE_FILE) SET (STATE_PTR); END; |
PL/I supports the RMS segmented key concept. Segmented keys are used when a single key cannot be made in contiguous fields of the record. The key's parts are split up over the record, or reordered within a contiguous part of the record. Segmenting the key has the advantage of using only one key to represent several fields that are always defined and sorted as a conceptual unit.
When there is a KEYFROM clause with a segmented key, PL/I takes its usual action of copying the key value into the record variable and then writing the variable directly to disk through RMS.
PL/I copies the one contiguous value to the position or positions specified by the RMS definition for the segmented key. This means it must break up the value into subfields or segments. Those fields are determined by the RMS segment sizes for the key. Thus, for a 4-segment key of 8 bytes and individual sizes of 1, 1, 4, and 2, respectively, it would break up the one contiguous key value ABCDEFGH as follows:
Then it copies each segment into its correct position in the record-the positions as specified by RMS, not your record variable structure declaration.
When RMS orders the records by the key, it reconstructs the original key value as one piece and sorts it that way. Thus the relative ordering of the segments within the record has no bearing on how the original value is sorted.
These actions are the same for nonsegmented keys in PL/I. They are treated as keys of one segment only, of the appropriate RMS-determined data type.
If you need to use segmented keys, be aware of the following considerations and constraints:
KEY(v)
Indicates that an existing record is to be accessed at the indicated key value (v). There is no movement of the key value. (The KEY option is valid on the READ and REWRITE statements.)KEYFROM(v)
Indicates that a new record is to be created at the position specified by the key value (v). Because RMS requires the key value to be embedded in the record, PL/I moves the value into the correct place in the record buffer that is specified by the FROM option of the WRITE statement.
Note that the key specified by the KEYFROM value is always the primary key, and that PL/I sets the key number to the primary index number (0). For segmented keys, PL/I copies the value into the correct key field positions.
Note also that the KEYFROM option is used on the WRITE statement only, not the REWRITE statement. When you use a REWRITE statement, you need to ensure that the key value is in the record by first using a READ statement.
PL/I signals the KEY condition when errors occur while keys for indexed sequential files are being processed. For example, if a key value specified on a READ statement specifies a key that does not exist, or if a WRITE statement attempts to write a record using a primary key value that already exists, the KEY condition is signaled.
You can write an ON-unit to detect and correct some of the more common key errors. For an example of an ON-unit that detects whether a record with a given key value was not found or whether an attempt was made to write a record whose key duplicates the value of an existing key, see Chapter 4.
Previous | Next | Contents | Index |