An Example Application



As good as theory might be, it can't compare to actually seeing how an application would be built and function. This application is a prescription filling program from a retail pharmacy program that was developed in the 1980s. The source code is available from sourceforge here.

What is in the Package
Looking at the Record Formats
Initialization Files
Building files
Making Indexes
Building applications

What is in the Package
Upon downloading and unpacking the source package, you will find two directories. The one we want to look at is pharm. In the pharm directory there are several sub directories. There are the required files and index directories. They are currently empty. There is the init directory. This directory contains the initialization data necessary to build the data files. There are two other directories as well. One is called src, which contains the application source code in C, and the other directory is named c++ which contains the same application in C++.

If you are too impatient to read this page, you can read the README file contained in the top level directory, follow it's instructions, and be up and running in minutes.

Looking at the Record Formats
Each file in this application is described by a record format description file. The files are found here. Let's look at one of the more complex files. It is the family file, and is named rxxfam. It's record format file is named rxxfam.rf.

The file contains 13 record formats. We'll start by looking at the first couple. Record format one is the family demographic record. It contains the information that is common to all of the family members; family name, address, phone, etc. Record format two contains information regarding the individual family member; thier first name, birth date, gender, and so forth. Record format four is used to indicate that the patient has a different last name than the main family record, and will immediately preceed the patient demographic record. Yes, you could have the different last name contained in the patient demographic record, but is the exception to the rule, and you can make better use of your database space that way. Record formats six through the end are individual prescription records. The actual prescription data (drug, date, amount, etc) is packed in the first field. Field two of each of these are of different sizes, so that you can have different lengths of instructions for each prescription, and do it, again, saving disk space. Remember that this application was written in the early '80s and memory and disk were at a premium.

Initialization Files
After you have built this application, you next need to build the database that it will use. Change to the init sub directory under pharm, and you will notice a series of files with names ending in .i and .t. The routine to make files requires the .i file. These are initialization files. The .t files are templates. They contain the responses to mkdf to build the datafile. They are just a convenience. The .i files bear closer examination, however.

The initialization files contain the base set of data record(s) that you wish to have in your data file. Each line in the file represents one data record. The members of the line are colon (:) seperated fields. The first field of a line is the record format number for that record. Following is the data for each field. If the data field is to be empty you can have a zero length entry for that field. Otherwise, the field has to be initialized to it's full width. Any fields left undefined when the end of line is reached are blank filled. So, for our family file format the first two lines in the initialization file reads

1:00001:GREEN :631 Pali St. :Sandy :UT:84070:5716061:Y:Y:
2:ROBERTA :061360:F:


This indicates that the first record will be format 1, and the data for each record is filled out for the entire record. Since the second record has five fields defined for it, the last two fields will be blank filled when the data file is generated. If the field actually contains a colon you escape it with a back slash, eg \:. You may also escape the back slash if you need to, \\. Fields that are defined as blobs can not have initialization data in the file. They should be initialized to nothing.

Building Files
Now that you have your initialization and template files built, it's time to generate your data files. Set your ROOT environment variable to point to where your database is to reside and issue the command:

mkdf rxxfam rxxfam.i < rxxfam.t

This will make the datafile rxxfam, and place it in your files directory. Again if you are impatient, in the example, you will find a script called makem. Just run this script, and it will build all of the files required for this example.

If you define a field as having zero length, that indicates it is a blob and needs to be treated differently.

Building Indexes
Indexes are necessary to get any data out of a data file. All data is retrieved by referring to an index name. So, before we build our end applications, we need to build programs that will generate indexes. In the pharmacy example, there are five indexes used. Initially, there were six, but this example didn't require one of them. Let's look at a sort routine.

To begin with, you don't include the dataman.h (or dataman.hh for C++) header. You include the sort.h header. This defines this as an index building program. The second big difference is that you don't begin by calling init_dataman, you begin by calling mkidx. You pass this function the arguments to main; argc and argv. This function defines the calling sequence for sort programs as:

sort_prog [-size -h host -r root] indexname file1 file2 ...filen

Where size is the key size. The default is 20 characters, the minimum is 1, and the maximum is 32. The host argument is the hostname where the database server is running. You may also have and environment variable name DSERVHOST to specify this. If you don't have the ROOT shell variable set, or you wish to override it, you can specify the database root as well. The first non optional argument is the name of the index to build, and the subsequent arguments are the names of the data files that will be sorted through.

The two other most important functions that you will be using during a sort program is sort and release. The sort function takes as it's argument the string that you want to associate with this record as it's key. The release function flushes the current record from memory and retrieves the next record in the data file. If the current record is the last one in the data file, it closes that file, opens the next named data file, and returns the first record from that file. It also sets the global _file switch to TRUE. You can use the when_file macro to test this value. After the first record in a data file has been released, this switch is set to FALSE.

Building Applications
Normal applications include the dataman.h(h) file. This defines this as an application program and not a sort program. The first function that should be called is the init_dataman function. The arguments to this function are the arguments to main; argc, and argv. This defines the calling sequence as:

app [-h host -r root] workfile

After this you call iopen to open indexs, use the varous get routines to retrieve data records associated with keys, call forward and back to directly retrieve records, and all of the rest of the functions to complete your application. When you have retrieved a data record, it is stored in a global variable that is pre-defined for you. In C, it is an array called mfld. In C++ it is in the record class instanciated as master, which contains an array of type field. So in C you refer to a field as mfld[n], where n is from 1 to he number of fields, and in C++ you refer to master.field[n]. The work file record is wfld[n], and workfile.field[n] respectively. The C++ fields are written as bounded arrays, so you worrying about that is not necessary.

Please look at the example programs for at least a little help on how to use the routines.