4.15 Miscellaneous RMS Functions



Dreadc(C-3) rereads a record once it has been located by one of the other function calls. A sample of rereading is done in the multi-user environment where a program first finds the record wanted, locks the record, rereads the desired record, makes its changes, stores the changes, and finally unlocks the record. For example:

/* move key into user record */

strncpy (subbuf.subscriber, subscriber,

sizeof (subbuf.subscriber));

if (dfindk (&subbuf, sub) < 0L)

printf ("record not found\n");

else

if (dclockw (sub) == 0)

printf ("record busy, try again\n");

else {

dreadc (&subbuf, sub);

/* make changes to record */

dupdate (&subbuf, sub);

dcunlock (sub);

}

Notice in this case that if the record is not found the first time nothing is locked, and only error reporting needs be done. The record must be re-read because another program may have had the record locked for changes when our program did the find. While our program waited for the lock, the other program wrote its changes and unlocked the file. By re-reading the record before making changes, we ensure that we have the most current instance of that record.

The functions dread(C-3) and dwrite(C-3) provide a low-level method of access to RMSfiles. They allow the user program to access records directly within a file without using the key values in a record. The two functions access records strictly by the record number specified.

Dread reads the record number specified. A sample call is:

recno = dread (&subbuf, recwanted, sub);

In this example, the variable recwanted is a long integer and contains the record number desired. If the record number is greater than the number of records in the RMSfile or if no data has been written at that record number, a -1 is returned. Otherwise, the record is read and returned into the user buffer.

Dwrite writes the contents of the user buffer into a particular record slot. Dwrite completely ignores the contents of the key values in the user buffer and overwrites data stored in the record. Any indexes associated with the RMSfile (including the primary key index) are not updated by dwrite. A sample call is:

recno = dwrite (&subbuf, recwanted, sub);

If the dwrite is successful, the original record number is returned. If it is not successful, a -1 is returned.

The record numbers returned by the different RMS functions should not be saved as a permanent means of locating a record. The record numbers indicate only the position of a record at that time the record was read. The record number returned by the functions is not identified with a particular record's contents. Record numbers point to one slot in an RMS data file and, if records have not been moved, can be used to relocate a record. If records have been moved, the record numbers cannot be used accurately to retrieve records again. In most RMSfile organizations, when the file is reorganized, the records are relocated to another record slot.

The remaining RMS functions provide auxiliary information about RMSfiles and errors.

Derrmsg(C-3) returns a pointer to a string of characters that describes the last I/O error that occurred in RMS. This message is reset so that future calls to derrmsg return a NULL pointer until another I/O error occurs. Derrmsg also returns NULL if no RMS errors have occurred since the program started execution. For example,

if ((fp = dlopen ("mag", "u")) == NULL) {

printf ("%s\n", derrmsg());

puts ("unable to open magazine file");

exit (1);

}

Derrmsg is especially helpful after a failed call to dlopen(C-3), dopen(C-3), dtopen(C-3), drlist(C-3), or dblist(C-3). With the open calls, derrmsg identifies the reason for an open failure (there are many possibilities). Some of the messages have a system message enclosed in brackets [ ]. The system messages are provided when a system call (like open(2), write(2), or read(2)) fails.

Derror(C-3) returns the error number of the last I/O error detected by RMS. The I/O error number is reset so that future calls to derror return zero until another I/O error occurs. An include file provides for symbolic definitions and commented descriptions of each error message:

#include <cbase/direr.h>

In most cases, the only error number of any interest is DEIFF. This error occurs when the RMS data file is full and a dinsert(C-3) is attempted. In this case, the record is not added, dinsert returns -1, and derror will return DEIFF (if called after dinsert).

NOTE: The RMS error handling routines save potential errors that may or may not be actual errors. For example, when inserting records into a hashed RMSfile, dinsert first scans all existing records with the same key. After the last key has been scanned, dinsert knows where to insert the new record. In this process, a "record not found" error is set by RMS. Dinsert ignores this error and continues. If derror is called after the dinsert call, the "record not found" error, ignored by dinsert, is returned. Even though the insertion succeeded, by calling derror it may appear to have failed. The rule to follow is to call derror or derrmsg only if an RMS function returns an error status.

Drecsiz(C-3) returns the size of the user record as specified by the call to drlist(C-3) or dblist(C-3). This function might be used as follows:

if ((mag = dopen ("magazine", "r")) == NULL) {

printf ("can't open magazine file\n");

exit (1);

}

if (drlist (maglist, mag) < 0L) {

printf ("%S\nbad field list for magazine file\n",

derrmsg());

dclose (mag);

exit (1);

}

magbuf = malloc (drecsiz (mag));

In this case, the program will have to derive the field offsets in the user record.

Dnrec(C-3) returns the number of records slots currently allocated to an RMSfile. For hashed RMSfiles, this number remains constant until the file is reorganized (see expandlf(C-1)). Sequential and indexed sequential RMSfiles grow as needed and this number increases accordingly. This means that the value returned by dnrec can change with time. Take care in how it is used. A sample call to dnrec would be:

mag_count = dnrec (mag);