| |CI2 Home|Literature|Support|Documentation|Y2K|Order|License| | |||
| Chapter 3 Using the Single-Key Functions
This chapter provides a general discussion of using the Single-Key functions of C-Index/II, and should be read before using these functions. A full description of all aspects of each function will be found in the C-Index/II Reference Guide. Description of Single-Key Functions The C-Index/II single-key functions are designed to be a generalized index and data storage system that does not make any assumptions about the nature of the information that is being stored. This allows considerable flexibility in the usage of the system. One method of using C-Index/II is as a standard B+Tree index file manager for the storage of keys pointing to data records. The keys and corresponding data record numbers are stored in the index file and these values are used to locate the data in a separate, fixed-length record file. C-Index/II however, also offers many other advantages. For example, another filing method unique to C-Index/II is to have the data associated with the key actually stored with the key. In this case, the data record number is not needed other than to resolve duplicate keys. This feature opens up many new programming possibilities not available from a standard B+Tree system. In addition, the data record stored with the key may vary in length up to 30K bytes. This feature allows the system to be used as a generalized data storage system in which information is retrieved by key value. Often an application will need to keep track of many small pieces of information. C-Index/II allows the programmer to store these pieces in an index file by keyed value without concern for the exact location of the pieces in the file. This use of C-Index/II can eliminate the need for slow and cumbersome searches through standard C files, and in this situation, C-Index/II is easier to use than standard C language file access routines.
The C-Index/II system allow multiple files to be open at once. For example:
File 1 File 2 File 3 .... File n
The maximum number of files open is determined by operating system. Within each file are 15 "key-indexes" (this number can be increased by recompiling the source code). Each key-index functions as a logically separate index, even though the information is physically stored in one operating system file. For example:
Index 1 Index 2 Index 3 .... Index 15
Each key-index contains a variable number of "entries". The maximum number of entries is determined by available space on the disk. For example:
Entry 1 Entry 2 Entry 3 .... Entry n
Each entry is made up of three parts:
Key Record Number Data
The default Key type is a zero-terminated string. It may also be other types if the file has been created with an Indexlist. The maximum key length is 240 bytes. The Record Number is a signed long integer. The Data portion of the entry is a sequence of bytes that may vary in length from 0 to 30K bytes. The length of the data portion of the entry is a function parameter specified by the program when adding or changing the entry. This length is automatically stored in the entry as an int type variable. Entries are sequentially positioned in the file according to the ASCII value of the key and the numeric value of the record number. Logically speaking, it is as though there are up to 15 index files open for each physical file open. Each file contains 20 key-indexes that are processed separately, although the keys for each "key-index" reside in one physical index file. The last five indexes are reserved for system use. Having 15 logical indexes available in a single file allows the programmer to develop complex key and data storage structures without having multiple files open. Any key or data information that is related to the application can be combined in a single file. To the application user, the entire structure would appear to be one file in the disk directory, facilitating the copying and deleting of the file. The programmer has the option to use separate physical files with one key-index in each file, or multiple key-indexes in a single file. The actual items of information stored in the index are referred to as "entries". Each entry consists of three parts:
The parameter structure contains two parts: file information variables and parameter variables. File information variables are items of information from the file header that control usage of the file space. These should not be changed in any way by the application program. Parameter variables can be accessed to communicate to and from the C-Index/II operations.
If a data length parameter value of zero is specified when reading entries, no data will be read and the return value of both dlen and retlen are invalid and must be ignored. To obtain the correct length of a record without reading the entire record, read data buffer length parameter must be set to at least 1. For example, cfind will not set psp->dlen with the following parameters:
cc = cfind(psp, 1, "SMITH", 0L, NULL, 0);
However it will return the length with the following call:
char tmpbuf; cc = cfind(psp, 1, "SMITH", 0L, tmpbuf, 1);
To allow the greatest flexibility in using C-Index/II, key values are always assumed to be duplicate. That is, the application program may add entries when the key portion is the same as an entry already in the index. The order of entries is always determined by the ASCII collating sequence of the key combined with the data record number. For entries in which the keys are identical but the data record numbers vary, the entry order is resolved by the increasing numerical value of the data record numbers. When the data is actually being stored in the entry by using a duplicate key, it is necessary for the application program to supply a unique data record number to resolve the problem of duplicate keys. This is accomplished with the cnextrec function which gets a unique long int number from the index header control information. The number maintained in the header is incremented by one each time cnextrec is called. This allows for a very large set of unique numbers. For example, it will take over 100 years to use up the full range of unique numbers in the signed long integer, assuming the extreme case of adding a new entry an average of once each second, 24 hours per day, 365 days per year. The file create functions (bcreate, ccreate)automatically sets the next record number that will be returned by cnextrec to 1. This number can also be set to any desired value using the csetrec function. The file create functions (bcreate, ccreate, etc) function creates a new C-Index/II file which contains two special data structures: the header record and one empty "node" for adding the first entry. The file create functions must be used to create these two structures in the new file before any information can be entered. The file open functions (bopen, mopen, copen) open an existing C-Index/II file. The close functions (mclose, cclose) close an open C-Index/II file. C-Index/II internally maintains a current entry pointer for each key-index. Whenever the program has performed an operation that either finds an entry or adds a new entry, the current pointer for that index is updated to point to the key that has been found or added. The current key pointer is used to determine where to find the next or previous key, and is also used with the operations that work with the current entry (see Using Current Entries). New index files are created using the bcreate operation. For example:
CFILE file1; /* declare parameter structure 1 */ int cc; /* code from create */
cc = bcreate(&file1, "file1.dat" EXCL, NATIVEMODE, NULL)
The name of the file is any valid file name that is permitted by the compiler create file function (see the compiler specific code and your compiler reference manual). If any error occurs in the low level create function (including invalid file names), the bcreate function returns a FAIL condition code value. If the bcreate function is successful, it returns an CCOK condition, and the file is now open so that indexing operations may be performed. Opening an Existing Index File To use a file that has previously been created and closed, the bopen operation must be used. For example:
CFILE file1; /* declare parameter structure 1 */ int cc; /* condition code from open */
cc = bopen(&file1, "file1.dat", EXCL, CRDWRITE, NULL);
If any error occurs in the bopen function (including invalid file name), the function returns a FAIL condition code. If the operation is successful, the function returns an CCOK condition code. Once the file has been successfully opened, indexing operations may be performed. To close the file after processing the mclose operation is used. For example:
CFILE file1; /* declare parameter structure 1 */ int cc; /* condition code from close */
/* open file for processing */ cc = bopen(&file1, "file1.dat", EXCL, CRDWRITE, NULL) . . . cc = mclose(&file1); /* close file after processing */
It is important that the close operation be performed after using the file. With the default C-Index/II settings and normal operating systems behavior, information will not be lost. However, with optional C-Index/II settings file information may be buffered. Also, some operating systems will buffer information incorrectly in memory until a close operation is performed. If the application program terminates before the mclose function is performed, the index may lose both recently added information and previously added information. For more information on this subject, refer to Chapter 5, "PowerFail Protection". When a new index file is created, it is automatically initialized with 20 empty indexes. The first 15 indexes are available to the application. After creating the file, entries can be added to these indexes. The last 5 indexes are reserved for internal use. cunqadd(psp, keyn, key, rec, data, dlen)
This operation adds a new key to the index, but note that duplicate keys are not allowed. If an exact match with the key is encountered a condition code of FAIL is returned. cdupadd(psp, keyn, key, rec, data, dlen)
This operation also adds a new key to the index, but duplicate keys are allowed. The addition of a duplicate key will always succeed unless there is also a matching record number for the duplicate key or some system type failure (such as a disk full condition). Duplicate key entries are arranged in the index according to the record number (in increasing order). When performing a find operation using a key that has duplicates in the index, the entry with the lowest record number will be encountered first. cchange(psp, keyn, key, rec, data, dlen)
This operation causes a change in the data portion of an existing entry. If an exact match (including Data Record Number) is not found, a condition code of FAIL will be returned. cchgcur(psp, keyn, data, dlen)
This operation also causes a change in the data portion of an existing entry. The entry that is changed is the current entry that has been found by a key locating operation. If there is no current entry, a condition code of FAIL is returned. For more details about current entries, refer to the section on "Finding Entries". csave(psp, keyn, key, rec, data, dlen)
The csave function will add a new entry to the index if the entry does not already exist. However, if an exact match is found, that is, both Key and Data Record Number match, the data portion of the entry will be changed to the passed data value. This allows the application program to perform an add or a change with a single function call without having to test for the existence of the entry first. Several operations allow the application program to find entries within the index. Entries may be found by both the key value and by relative position in the index. The entry location operations return two items of information:
cfind(psp, keyn, key, rec, data, dlen)
This operation performs a search through the index to find an entry that has a key of equal or greater positional value than the specified key. A condition code is returned by the function call indicating the result of the search:
cnext(psp, keyn, data, dlen)
This operation finds the next entry in the index after the location of the current pointer. The current pointer is then updated to the new location and the entry information is returned to the calling routine. A condition code is returned to indicate the result:
cprev(psp, keyn, data, dlen)
This operation finds the entry located in the index before the current pointer. The current pointer is then updated to the new location and the entry information is returned to the calling routine. A condition code is returned to indicate the result:
cfirst(psp, keyn, data, dlen)
This operation finds the first entry in the index. The current pointer is then updated to the new location and the entry information is returned to the calling routine. A condition code is returned to indicate the result:
clast(psp, keyn, data, dlen)
This operation finds the last entry in the index. The current pointer is then updated to the new location and the entry information is returned to the calling routine. A condition code is returned to indicate the result:
cgetcur(psp, keyn, data, dlen)
This operation finds the current entry in the index. The location of the current pointer is not changed, and the entry information is returned to the calling routine. A condition code is returned to indicate the result:
Entries that have been added to an index may also be deleted. The cdelete operation locates the entry to delete by automatically calling the cfind function before deleting the key. The cdelcur operation deletes the entry indicated by the current pointer that was set by a previous operation. After a successful delete operation, the current entry pointer indicates where the entry existed before deletion. However, because an entry no longer exists at this location, operations that work with the current entry (such as a subsequent cdelcur) will return a FAIL condition code. A typical usage of cdelcur in an application program is to use cnext or cprev in combination with cdelcur to delete a series of entries located together in the index. The delete operations are as follows: cdelete(psp, keyn, key, rec)
In this operation, the entry is found by using the key and record number values passed. If an exact match is not found an error is returned. If there are duplicate entries (identical key and data record numbers), the first entry in the duplicate sequence will be deleted. Care should be used when deleting duplicate records. This function returns the following condition codes:
cdelcur(psp)
In this operation, the current entry is deleted. If a current key does not exist, no deletion occurs. This function is useful when the application program finds a key before deleting it. In this case, the entry does not need to be relocated. This is especially important when using duplicate key entries. The function returns the following condition codes:
Tutorial Program for Single-Key Functions The C-Index/II Tutorial demonstration program is designed to allow you to try C-Index/II operations, and view the results without having to do any programming. This demonstration program is called tutor.exe and is located on the utilities disk. It was designed to be used with an IBM or IBM compatible computer. If you are using another type of system, refer to the documentation on the disk for more information on using the tutorial on your system. The Tutorial uses 2 files that are supplied with the system: tutora.ind and tutorb.ind. These files have been initialized for this demonstration. To run the Tutorial type at the operating system prompt: TUTOR <return>
Tutor will automatically begin execution, and will respond with a display. The screen will show a list of commands in upper case, including parameters that may be required for each command. At the bottom of the screen will be:
Enter Function :
Although Tutor will accept lower case commands, for the sake of simplicity, only upper case characters are used in these examples. Most of the commands are self-explanatory. To begin, however, you must open a file. Tutor uses two psp's, and you can switch between them with the CHGPSP command. There is always one current psp, and any operations use this current psp. Tutor starts with psp 1 current, so unless you begin by changing the active psp, the first open will open tutora.ind and will use psp 1. To perform this, type: OPEN <Return>
If you want to open the other file, you must first switch to psp 2 with the CHGPSP command and then execute another open. Tutor will sense psp 2 and open tutorb.ind. To get the menu again, type: HELP <return>
HELP may be typed at any time between operations. Do not type HELP in the middle of a command, as it will be interpreted as a parameter value for that operation. If in doubt about an operation, erase the entire command line using backspace, then type HELP. The help information will also be displayed when you press return on a blank entry line. The functions that expect parameters should be separated by a space. For example, the unique add operation requires the parameters to be indicated in the following format: UNQADD <key> <rec> <data>
To add a unique entry with the key value "ABC", a record number of 13, and the data string "ABC Data", type: UNQADD ABC 13 ABC Data <Return>
Note that the last parameter, data, can contain spaces. For any operation with data, the data is expected as the last parameter, and is read to the end of the command line. You are encouraged to experiment with this tutorial. There is also a file tutora2.ind that is a duplicate of tutora.ind. You can use tutora2.ind to restore the file to its original state. You should refer to the reference section on the individual functions while using the tutorial in order to understand what the functions are supposed to do. Be sure to close both psps before exiting so your work will be saved. To exit the tutorial type: BYE <Return>
C-Index/II Home Pagewww.triosystems.com © Copyright 1996 - 1999 Trio Systems LLC |