Library Overview
The RECITAL/Library is a library of functions that provide shared read write access to RECITAL database table (.dbf) files, index (.ndx & .dbx) files and memo (.dbt) files. Applications written in 'C' can use the RECITAL/Library to manipulate data stored in the RECITAL files. On OpenVMS any 3GL that conforms to the OpenVMS procedure calling standard can also use the RECITAL/Library. When using the RECITAL/Library with FORTRAN and COBOL on OpenVMS the dbstring() function should be used to format 'C' strings for use as parameters to these functions.
For performance reasons, all information retrieved and placed into database tables is arranged in character arrays. Functions are provided for converting portions of these character arrays into non-character data. When writing these character arrays to database tables, any portion of the array that is representative of a non-character field is automatically converted to the proper data type.
Using the RECITAL/Library Functions
The RECITAL/Library works with the following file types:-
- Database table files (.DBF) that contain fixed length records.
- Index files (.NDX) and tagged index files (.DBX) that contain keys to the .DBF file enabling fast access to the data records.
- Memo files (.DBT) that store free formatted text for 'memo' fields in the database table.
This section explains how the RECITAL/Library functions relate to these file types.
Database Files
A RECITAL database file (.DBF) stores the data of a particular application. The data is divided into units of a fixed size called records. The RECITAL/Library functions operate on these units. For example, the dbappend() or dbputr() functions write a record to a .DBF file, dbgetr() reads a record from a .DFB file and dbupdr() function updates an existing record. Sub-units of records are called fields. At the head of each database table file, RECITAL stores information relating to the layout of the records held in the database table. The database table structure is comprised of:-
- PROLOG
- FIELD DEFINITIONS
- FIELD DESCRIPTIONS
- DATABASE RECORDS
Each field/column can be described by the following 'C' structure that is defined in the include file "dbl.h":-
typedef struct { char fieldnm[11]; /* Field name */ char type; /* Type of data in the field: 'C' = character 'N' = numeric 'L' = logical 'D' = date 'M' = memo */ int width; /* Field width */ int dec; /* Number of decimal places (for numeric fields only) */ int rpos; /* Record buffer position */ } dBFIELD;
NOTE: rpos is the physical starting position of the column in the record buffer. Position 0 is for the deletion marker, so the first column will start at 1, the next position will be determined by the storage width of the previous column.
When creating a .DBF file, remember the following:-
- The maximum length of a record is 4000 bytes;
- The maximum number of fields in a record is 256;
- The maximum length of a character field is 254 bytes.
The created .DBF file must be opened with the dbopen() function before it can be accessed. After the file is opened, a record can be inserted by using the dbputr() function or appended by using dbappend().
It is important to consider that when a record is inserted all the records that will follow it in the .DBF file are shifted down to create a space for the new record. To avoid this time consuming shifting operation it is a good idea to insert a new record after the last inserted record. The record number of the record to be inserted will be the number of current records +1. The number of inserted records can be obtained by using the dbsize() function.
Similarly, when a record is deleted, all the following records are shifted up to close the "gap" between the records. In this case, to avoid shifting, one can delete the record logically not physically. When a record is deleted logically, it is marked deleted but physically remains in the file. The record is considered "INACTIVE". The record's status (ACTIVE or INACTIVE) can be obtained by using the dbgetr() function. The dbflush() function writes the contents of the buffer used for .DBF files onto the disk. It does not have to be used in your application program, but it allows you to control the I/O. The .DBF file must be closed with the dbclose() function before your program exits.
Index Files
Index files contains index keys/record numbers pairs for every record in a database file. Keys and their associated record numbers are organized in a B+ tree structure, and the keys appear sorted in an ascending order. This organization permits fast access to a particular key/record number pair. By supplying a key to the functions dbtkey() / dbxtkey(), its associated record number can be obtained. This record number can be used to directly access the associated record in a database table.
Index files are created using the dbicreat() or dbxcreate() functions. When creating an index file, you must name the key type (character (C), date (D), or numeric (N)) and the key expression which is usually the name of one or more record fields (e.g., "SSN" or "NAME" + BIRTHDATE"). The dbkexpr() or dbxkexpr() functions can be used later to retrieve a key expression from an existing index file. An existing index file must be opened with the dbiopen() or dbxopen() functions. After the file is opened, you can add a key to it with the dbakey() / dbxakey() functions or remove a key by using the dbrmvkey() / dbxrmvkey() functions.
The RECITAL/Library uses an internal access pointer that is positioned at the top of an .NDX file when the file is opened. When the dbtkey() / dbxtkey() functions translates a key to the record number, they position the pointer to the position where that key is found. An application can obtain the current key by using the dbckey() / dbxckey() functions, next key by using the dbnkey() / dbxnkey() functions and previous key by using the dbpkey() / dbxpkey() functions. The access pointer can be repositioned at the top of an index file by using the dbrewind() / dbxrewind() functions or moved to the end by using the dbfwd() / dbxfwd() functions. The dbgetrk() / dbxgetrk() functions translate a key into record number and then retrieve the record. Given a key, these functions can be used to get a record in one step. The dbiflsh() / dbxflsh() functions flush the contents of the index buffer cache. Before an application program exits, the index file must be closed with the dbiclose() / dbxclose() functions, otherwise the file may not be updated properly.
Memo Files
Some data that needs to be kept in a database can be hard to organize in any of the character, numeric, date or logical fields of a .DBF. In this case, a .DBT file should be created. A .DBT file is used to store free-format text related to 'memo' fields in a database. The memo fields in a .DBF file occupy four bytes which indicate where a particular memo is located in a .DBT file. A memo field of a record can be retrieved by using the dbgetr(), dbgetnr(), dbgetpr() or dbgetrk() functions. Having retrieved the memo field, you can read a memo from a .DBT file by using the dbgetm() function. A memo can be stored in a .DBT file by using the dbputm() function. A memo field can be added or updated in the corresponding .DBF file by using dbputr(), dbputrk(), or dbupdr() functions.