HP OpenVMS Systems Documentation |
HP BASIC for OpenVMS
|
Previous | Contents | Index |
The GET statement moves a record from a file to a record buffer and makes the data available for processing. GET statements are valid on sequential, relative, and indexed files. You should not use GET statements on terminal-format files or virtual array files.
For sequential files, a sequential GET retrieves the next record in the file. For relative files, a sequential GET retrieves the next existing record. For indexed files, a sequential GET retrieves the record with the next ascending or descending value in the current key of reference, depending on that key's collating sequence.
Table 13-2 shows the current record and next record pointers after a GET operation. Note that the values of these pointers vary, depending on whether or not the previous operation was a FIND.
Record Access Mode |
File Type |
Current Record |
Next Record |
---|---|---|---|
Sequential GET
with FIND |
Sequential | Record found | Current record + 1 |
Relative | Record found | Next existing record | |
Indexed | Record found | Next record in current key | |
Sequential GET
without FIND |
Sequential | Next record | Next record + 1 |
Relative | Next existing record | Next existing record + 1 | |
Indexed | Next record in current key |
Record following next
record in current key |
|
Random GET | All | Record specified | Next record in succession |
If you precede a sequential GET operation with a FIND operation, the current record is the one located by FIND. If you do not perform a FIND operation before a sequential GET operation, the current record is the next sequential record.
The following example shows the use of the GET operation to sequentially access records in an indexed file. The example opens an indexed file and displays the first 25 records with serial numbers greater than AB2721 in ascending primary key value order.
MAP (Bec) STRING Owner = 30%, LONG Vehicle_number, & STRING Serial_number = 22% OPEN "VEH.IDN" FOR INPUT AS FILE #2%, & ORGANIZATION INDEXED, PRIMARY KEY Serial_number, & MAP Bec, ACCESS READ GET #2%, KEY #0% EQ "AB2721" FOR I% = 1% TO 25% GET #2% PRINT "Vehicle Number = ";Vehicle_number PRINT "Owner is: ";Owner PRINT NEXT I% |
The following example performs random GET operations by specifying a record number:
MAP (Bec) STRING Owner = 30%, LONG Vehicle_number, & STRING Serial_number = 22% OPEN "VEH.IDN" FOR INPUT AS FILE #2%, & ORGANIZATION SEQUENTIAL FIXED, & MAP Bec, ACCESS READ INPUT "Which record do you want";A% WHILE (A% <> 0%) GET #2%, RECORD A% PRINT "The vehicle number is", Vehicle_number PRINT "The serial number is", Serial_number PRINT "The owner of vehicle";Vehicle_number; "is", Owner INPUT "Next Record";A% NEXT CLOSE #2% END |
You can specify an ALLOW clause in a GET statement if you have opened the file with ACCESS MODIFY or ACCESS WRITE and UNLOCK EXPLICIT. The ALLOW clause lets you control the type of lock RMS places on the retrieved record. ALLOW NONE specifies that no other users can access this record (this is the default). ALLOW READ lets other access streams have read access to the record. That is, other users can retrieve the record, but cannot perform DELETE, PUT, or UPDATE operations on it. ALLOW MODIFY lets other access streams perform GET, DELETE, or UPDATE operations on the record.
If you are trying to access a locked record, BASIC signals "Record/bucket locked" (ERR=154). However, if you only need to read this record, you can override the lock with the REGARDLESS clause. The REGARDLESS clause allows you to read a locked record. Use caution when using the REGARDLESS clause because a record accessed in this way might be in the process of being changed by another program.
Alternatively, you can also specify the WAIT clause on a GET statement;
the WAIT clause allows you to handle record locked conditions by
waiting for the record to become available. Note that if a WAIT clause
is specified on a GET operation to a unit-record device such as a
terminal, the integer expression indicates how long to wait for the I/O
to complete, rather than how long to wait on a record locked condition.
For more information, see Section 13.6.9.
13.6.5 Writing Records
For a file opened with ACCESS WRITE or ACCESS MODIFY, the PUT statement moves data from the record buffer to a file using the I/O buffer. PUT statements are valid on RMS sequential, relative, and indexed files. You cannot use PUT statements on terminal-format files or virtual array files.
Sequential access is valid on RMS sequential, relative, and indexed files. For sequential, variable, and stream files, a sequential PUT operation adds a record at the end of the file. For sequential fixed and relative files, PUT writes records sequentially or randomly depending on the presence of a RECORD clause. For indexed files, RMS stores records in order of the primary key's collating sequence; therefore, you do not need to specify a random or sequential PUT. Table 13-3 shows the record context after both random and sequential PUT operations.
Record Access Mode |
File Type |
Current Record |
Next Record |
---|---|---|---|
Sequential PUT | Sequential | None | End of file |
Sequential PUT | Relative | None | Next record |
Sequential PUT | Indexed | None | Undefined |
Random PUT | Relative | None | Unchanged |
After a PUT operation, the current record pointer has no value. However, the value of the next record pointer changes depending on the file type and the record access mode used with the PUT operation. In a sequential, stream, or variable file, records can only be added at the end of the file; therefore, the next record after PUT is the end of the file. In a relative, sequential, or fixed file, the next record after a PUT operation is the next logical record.
The following example opens a sequential file with ACCESS APPEND specified. For sequential files, this is almost identical to ACCESS WRITE. The only difference is that, with ACCESS APPEND, BASIC positions the file pointer after the last record in the file when it opens the file for processing. All subsequent PUT operations append the new record to the end of the existing file.
MAP (Buff) STRING Code = 4%, Exp_date = 9%, Type_desig = 32% OPEN "INV.DAT"FOR INPUT AS FILE #2%, & ORGANIZATION SEQUENTIAL FIXED, ACCESS APPEND, & MAP Buff WHILE -1% INPUT "What is the specification code";Code INPUT "What is the expiration date";Exp_date INPUT "What is the designator";Type_desig PUT #2% NEXT |
If the current record pointer is not at the end of the file when you attempt a sequential PUT operation to a sequential file, BASIC signals "Not at end of file" (ERR=149).
In the following example, the PUT statement writes records to an indexed file. In this case, the error message "Duplicate key detected" (ERR=134) indicates that a record with a matching key field already exists, and you did not allow duplicates on that key.
10 MAP (Purchase_rec) STRING R_num = 5, & Dept_name = 10, & Pur_dat = 9 20 OPEN "INFO.DAT"FOR OUTPUT AS FILE #2, & ORGANIZATION INDEXED FIXED, ACCESS WRITE, & PRIMARY KEY R_num, MAP Purchase_rec 30 WHILE -1% INPUT "Requisition number";R_num INPUT "Department name";Dept_name INPUT "Date of purchase";Pur_dat PRINT PUT #2% NEXT |
Requisition number? 2522A Department name? COSMETICS Date of purchase? 15-JUNE-1985 Requisition number? 2678D Department name? AUTOMOTIVE Date of purchase? 15-JUNE-1985 Requisition number? 4167C Department name? AUTOMOTIVE Date of purchase? 6-JANUARY-1985 Requisition number? 2522A Department name? SPORTING GOODS Date of purchase? 25-FEBRUARY-1985 %BAS-F-DUPKEYDET, Duplicate key detected -BAS-I-ON_CHAFIL, on channel 2 for file USER$$DISK:[MAGNUS]INFO.DAT;8 at user PC 0017E593 -BAS-O-FROLINMOD, from line 30 in module DUPLICATES -RMS-F-DUP, duplicate key detected (DUP not set) |
The DELETE statement removes a record from a file that was opened with ACCESS MODIFY. After you have deleted a record you cannot retrieve it. DELETE works with relative and indexed files only.
A successful FIND or GET operation must precede the DELETE operation. These operations make the target record available for deletion. In the following example, the FIND statement locates record 67 in a relative file and the DELETE statement removes this record from the file. Because the cell itself is not deleted, you can use the PUT statement to write a record into that cell after deleting its contents.
FIND #1%, RECORD 67% DELETE #1% |
There is no current record after a deletion. The next record pointer is unchanged. |
The UPDATE statement writes a new record at the location indicated by the current record pointer. UPDATE is valid on RMS sequential, relative, and indexed files.
UPDATE operates on the current record, provided that you have write access to that record. In order to successfully update a variable-length record, you must know the exact size of the record you want to update. BASIC has access to this information after a successful GET operation. If you have not performed a successful GET operation on the variable-length record, then you must specify a COUNT clause in the UPDATE statement that contains the record size information.
If you are updating a variable length record, and the record that you want to write out is of different size than the record you retrieved, you must use a COUNT clause.
An UPDATE will fail with the exception "No current record" (ERR=131) if you have not previously established a current record with a successful GET or FIND. Therefore, when updating records you should include error trapping in your program to make sure all GET operations execute successfully.
An UPDATE operation on a sequential file is valid only when:
The following program searches to find a record in which the L_name field matches the specified Search_name$. Once this record is found and retrieved, the Rm_num field of that record is updated; the program then prompts for another Search_name$. If a match is not found, BASIC prints the message "No such record" and prompts the user for another Search_name$. The program ends when the user enters a null string for the Search_name$ value.
20 MAP (AAA) STRING L_name = 60%, F_name = 20%, Rm_num = 8% 30 OPEN "STU.DAT"FOR INPUT AS FILE #9%, & ORGANIZATION SEQUENTIAL FIXED, MAP AAA 50 INPUT "Last name";Search_name$ 55 Search_name$ = EDIT$(Search_name$, -1%) 60 IF Search_name$ = "" THEN GOTO 32010 END IF 65 RESTORE #9% 70 WHEN ERROR IN 75 GET #9% WHILE Search_name$ <> L_name USE IF ERR=11 THEN PRINT "No such record" CONTINUE 50 ELSE EXIT HANDLER END IF END WHEN 80 INPUT "Room number";Rm_num 90 UPDATE #9% 100 GOTO 50 32010 CLOSE #9% 32030 PRINT "Update complete" 32767 END |
An UPDATE operation invalidates the value of the current record pointer. The next record pointer is unchanged. |
When you update a record in a relative variable file, the new record can be larger or smaller than the record it replaces, provided that it is smaller than the maximum record size set for the file. When you update a record in an indexed variable file, the new record can also be larger or smaller than the record it replaces. The updated record:
The following program updates a specified record on an indexed file:
MAP (UPD) STRING Enrdat = 8%, LONG Part_num, Sh_num, REAL Cost OPEN "REC.ING"FOR INPUT AS FILE #8%, & INDEXED, MAP UPD, PRIMARY KEY Part_num INPUT "Part number to update";A% Loop1: WHILE -1% GET #8%, KEY #0%, EQ A% INPUT "Revised Cost is";Cost UPDATE #8% INPUT "Next Record";A% IF A% = 0% THEN EXIT Loop1 END IF NEXT CLOSE #8% END |
If the new record either omits one of the old record's alternate key
fields or changes one of them, the OPEN statement must specify a
CHANGES clause for that key field when the file is created. Otherwise,
BASIC signals the error "Key not changeable" (ERR=130).
13.6.8 Controlling Record Access
When you open a file, BASIC allows you to specify how you will access the file and what types of access you will allow other running programs while you have the file open.
If you open a file for read access only (ACCESS READ), BASIC by default allows other programs to have unrestricted access to the file. You can restrict access with an ALLOW clause only if the file's security constraints allow you write access to the file.
BASIC by default prevents access by other programs to any file you open with ACCESS WRITE, ACCESS MODIFY, or ACCESS SCRATCH (sequential files only). This default action is equivalent to specifying the OPEN statement ALLOW NONE clause. To allow less restrictive access to the open file, specify ALLOW READ or ALLOW MODIFY.
When a file is open for read access only and you have not restricted access to other programs with ALLOW NONE, BASIC allows other programs to read any record in the file including records that your program is concurrently accessing. However, when you retrieve a record with the GET statement from a file you have opened with the intent to modify, BASIC normally restricts other programs from accessing that record. This restriction is called locking.
To allow other programs to access a record you have locked, you must release the lock on the record in one of the following ways:
In addition to the capability of restricting access through the OPEN statement ALLOW clause, BASIC allows programs to explicitly control record locking on each record that is retrieved. To use explicit record locking on a file, the OPEN statement must include an UNLOCK EXPLICIT clause. You may then optionally specify an ALLOW clause on the GET and FIND statements. The ALLOW clause on a GET or FIND statement specifies the type of access allowed by other programs to the record while you are accessing it. The following statement specifies that other programs may read but not modify the records you have locked:
GET #1, ALLOW READ |
If you specify UNLOCK EXPLICIT when opening a file, all records that
you retrieve remain locked until you explicitly unlock them with a
FREE, UNLOCK, or CLOSE statement.
13.6.9 Gaining Access to Locked Records
If you are trying to access a record that is currently locked, one possible solution is to use the REGARDLESS clause on the GET or FIND statement. The REGARDLESS clause is useful when you are interested in having only read access to the specified record. Be aware, however, that using the REGARDLESS clause to read a locked record can lead to unexpected results because the record you read can be in the process of being changed by another program.
Another solution is to include a WAIT clause on the GET or FIND statement. Note that you cannot specify a WAIT clause and a REGARDLESS clause on the same statement line. By specifying the WAIT clause, you can tell RMS to wait for a locked record to become available. You can optionally specify an integer expression from 0 to 255 with the WAIT clause. This integer expression indicates the number of seconds RMS should wait for a locked record to become available. If the record does not become available within the specified number of seconds, RMS signals the error "Keyboard wait exhausted" (ERR=15).
If you do not specify an integer expression with the WAIT clause, RMS waits indefinitely for the record to become available. Once the record becomes available, RMS delivers the record to the program.
Note that a deadlock condition can occur when you cause RMS to wait indefinitely for a locked record. A deadlock condition occurs when two users simultaneously try to access locked records in each other's possession. When a deadlock occurs, RMS signals the error, "RMS$_DEADLOCK". In turn, HP BASIC signals the error, "Detected deadlock error while waiting for GET or FIND" (ERR=193). To handle this error, you can either stop trying to access the particular record, or, if you must access the record, free all locked records (regardless of the channel) and then attempt the GET or FIND again. You need to unlock all records because you cannot know which record the other process wants.
If the timeout value specified in the WAIT clause is less than the SYSGEN parameter DEADLOCK_WAIT, then a "Keyboard wait exhausted" (ERR=15) message can indicate that either the record did not become available during the specified time, or there is an actual deadlock situation. However, if the timeout value is greater than the SYSGEN parameter DEADLOCK_WAIT, the system correctly specifies that a deadlock situation has occurred. |
The following example uses the WAIT clause to overcome a record locked condition and traps the resulting error condition:
MAP (worker) STRING first_name = 10, & last_name = 20, & badge_number = 6, & LONG dept_number MAP (departments) STRING dept_name = 10, & LONG dept_code OPEN "Employee_data.dat" FOR INPUT AS FILE #1%, & INDEXED FIXED, MAP worker, ACCESS MODIFY, & PRIMARY badge_number OPEN "departments.dat" FOR INPUT AS FILE #2, & INDEXED FIXED, MAP departments, ACCESS MODIFY, & PRIMARY dept_code WHEN ERROR IN WHILE -1% GET #1, WAIT WHEN ERROR USE time_expired_handler GET #2%, KEY #0 EQ dept_number, & WAIT 10% END WHEN PRINT badge_number, dept_name NEXT USE SELECT ERR CASE = 11% PRINT "End of file reached" CLOSE 1%, 2% CASE = 193% PRINT "Deadlock detected" UNLOCK #2% RETRY CASE ELSE EXIT HANDLER END SELECT END WHEN HANDLER time_expired_handler IF ERR = 15% OR ERR = 193% THEN PRINT "Department info not available for:" PRINT "Employee ";badge_number PRINT "Going on to next record." CONTINUE ELSE EXIT HANDLER END IF END HANDLER END PROGRAM |
The first WHEN ERROR block traps any deadlock conditions. The WHEN ERROR handler unlocks the current record on channel #2 in case another program is trying to access it and then retries the operation. The detached handler for the second WHEN ERROR block traps timeout errors and deadlock errors. If the desired information does not become available in the specified amount of time, or a deadlock condition occurs, the employee's badge number is printed out with an appropriate message, and the GET statement tries to retrieve the next record in the sequence.
Previous | Next | Contents | Index |