Dec 072017
 
CDB network-model ISAM database package. Version 1.20. Microsoft C and Turbo C support. Includes a Data Definition Language.
File CDB120.ZIP from The Programmer’s Corner in
Category C Source Code
CDB network-model ISAM database package. Version 1.20. Microsoft C and Turbo C support. Includes a Data Definition Language.
File Name File Size Zip Size Zip Type
CDB.TXT 96498 17016 deflated
DBDLIST.EXE 11381 7200 deflated
DBMGR.H 13524 2643 deflated
DDLP.EXE 21127 11620 deflated
MSCCDBL.LIB 37523 14376 deflated
MSCTEST.MAK 222 124 deflated
ORDER.TXT 1652 398 deflated
REGISTER.TXT 1504 260 deflated
TCCDBL.LIB 37888 12369 deflated
TCTEST.MAK 158 104 deflated
TEST.C 5076 1361 deflated
TEST.DDL 952 306 deflated
UPDATES.TXT 3275 1432 deflated

Download File CDB120.ZIP Here

Contents of the CDB.TXT file















CDB


Copyright (C) 1991 by Daytris
All rights reserved



Revised: May 20th, 1991


INTRODUCTION


Overview

CDB is a sophisticated database toolkit for MS-DOS and UNIX
developers. CDB includes the following features:

- Quick data access through a sophisticated multi-key ISAM
implementation.

- Multiple data models. Both relational and network data
models are implemented in CDB. The network model gives the
developer the ability to create relationships between
records without storing unique keys in those records.

- Data Definition Language (DDL) for defining database layouts.
The DDL is compiled into a binary format which is used by the
database server as a roadmap. Using this concept, a
developer can define and re-define a database with minimal
effort and absolutely no code changes. The DDL is patterned
after C for ease of programming.

- Over 30 predefined database function calls for complete
control of the database.

- Portability. CDB is written entirely in C for portability
and source code is included with your purchase. A version
of CDB is also available for the MS-Windows platform.
Contact the developers for more information about this
product.

- C++ compatibility. The library is callable from both C and
C++.

- Automatic re-use of deleted database space. There is no need
for database reorganization. Deleted space is automatically
reused by CDB.

- Low overhead. The CDB database engine requires an extremely
small amount of memory to operate.

- Royalty-free distribution rights. Whether you have one
customer or thousands, you pay for CDB just once for each
environment that you are using.


Obtaining CDB

Refer to the document included in this release, ORDER.TXT, to order
CDB. Your purchase will include CDB libraries, utilities, royalty-
free use of library functions, full library and utility source code
and make files. A printed manual will also be included.


Future Enhancements

Listed below are some of the enhancements planned for CDB. Any
suggestions would also be greatly appreciated.

- Multi-user database access. Networks and/or protocols to be
supported are currently undefined.

- Performance enhancements.


Contacting the Developers

CDB was developed solely by Daytris. If you have a question about
the product or any suggestions please contact us at the phone
number listed below. Or if you prefer, you can send us electronic
mail on any of the information services listed.

Daytris
81 Bright Street, Suite 1E
Jersey City, NJ 07302
201-200-0018

CompuServe:72500,1426
BIX: daytris
GEnie: t.fearn


GETTING STARTED


Unpacking

CDB is distributed in self-extracting ZIP files. When you first
unpack your software, you may want to verify that you have a
complete set. If you have the Test Drive version, you should have
the files included in CDB.EXE. If you have purchased CDB, you
should have the files included in both CDB.EXE and CDBSRC.EXE.
The contents of each are listed below.

CDB.EXE

File NameDescription
--------- -----------

CDB.TXT This document.
ORDER.TXTOrder form for CDB.
REGISTER.TXTRegistration form for CDB.
README.TXTLatest CDB info.
UPDATES.TXTHistory of updates made to CDB.
MSCCDBL.LIBCDB library. Microsoft C large model.
TCCDBL.LIBCDB library. Turbo C large model.
DBDLIST.EXEDatabase Definition (DBD) file display
utility.
DDLP.EXEDatabase Definition Language Parser.
TEST.C TEST do nothing program.
TEST.DDLTEST Data Definition Language File.
DBMGR.H CDB header file.
MSCTEST.MAKMake file for TEST (Microsoft C).
Microsoft NMAKE and UNIX make compatible.
TCTEST.MAKMake file for TEST (Turbo C). Microsoft
NMAKE and UNIX make compatible.


CDBSRC.EXE

File NameDescription
--------- -----------

LICENSE.TXTDaytris software license agreement.
MSCLIB.MAKLibrary make file (Microsoft C).
Microsoft NMAKE and UNIX make compatible.
TCLIB.MAKLibrary make file (Turbo C). Microsoft
NMAKE and UNIX make compatible.
DBADD.C Library source file.
DBUPD.C .
DBDEL.C .
DBFIND.C.
DBGET.C .
DBCURR.C.
DBFILE.C.
DBMGR.C .
DBPAGE.C.
DBSLOT.C.
DBTALK.C.
DBFUNCS.C.
DBMGR.H CDB header file.
DBXTRN.HExternal definitions header file.
STDINC.HHeader file that includes other header
files used in CDB.
DDLP.MAKMake file for DDLP. Microsoft NMAKE and
UNIX make compatible.
MAIN.C DDLP source file.
DDLP.C .
PARSE.C .
ERROR.C .
DDLP.H DDLP header file.
DBDLIST.MAKMake file for DBDLIST. Microsoft NMAKE and
UNIX make compatible.
DBDLIST.CDBDLIST source file.


THE NETWORK DATABASE MODEL


Introduction

CDB provides both relational and network model features. The use
of both models in a data design can greatly increase the
performance of your database. For those of you who are already
familiar with the relational database concepts, you will find the
network model implementation very refreshing. For those of you
who aren't familiar with the relational model, a very brief
description of relational concepts follows.


The Relational Model

In a relational database, data is stored in a series of tables.
Each table consists of a number of columns, which identify a
particular type of data, and rows, which correspond to a particular
record in the table.

Individual records can be retrieved using the key fields defined
for the table. If the developer has the desire to make an
association between two tables, unique key fields must be defined
in both records and unique data must be stored for retrieval to
take place.


What is the Network Model?

This model allows you to define relationships between records
through constructs called sets. A set defines a one-to-many
relationship between two tables.

In a relational model, records can only be related (connected)
by storing unique keys in both tables. This method creates
additional unwanted overhead. Duplicate data is stored in both
records and duplicate indexes must be managed.

Using the network model, records are connected by directly storing
data pointers inside the record. Where the relational model
requires multiple disk accesses to locate a related record, the
network model allows the record to be located in a single disk
access. Disk space is also saved when sets are used because no
index is required.

Another advantage of using the network model is the flexibility
of owner/member relationships. A record may own multiple record
types. A record may also be owned by multiple owner records. An
example of this would be a 'client' record owning 'invoice'
records and also owning 'address' records. In turn, an 'invoice'
could also own 'address' records, perhaps a shipping and billing
address. This kind of flexibility gives the developer the power
to define complex data relationships with relative ease.


THE DATA DEFINITION LANGUAGE

Introduction

The Data Definition Language is used for defining a database model.
The language is basically a superset of C structure definitions.
If you are familiar with defining C structures, the DDL should be
very easy to pick up on.

The DbOpen function call loads a binary image of a DDL file. The
binary image is created by compiling the DDL file into a DBD
(Database Definition) format. A DDL compiler is included with this
release, DDLP.EXE (Data Definition Language Parser).


An Example:

/* sampledb.ddl */

prefix ABC;

struct client
{
connectaddress key street;
key longclientnbr;
key charname[31];
chardescription[61];
doublebalance;
};

struct address
{
charstreet[31];
charcity[21];
charsate[3];
key charzip[11];
key chartelephone[13];
charfax[13];
};

struct setup
{
key longnextclientnbr;
};


Notice the close resemblence to C structure definitions. The only
differences are the prefix, connect, and key words.



prefix

The prefix is used internally by the database library when a new
database file must be created. In the SAMPLEDB.DDL shown above,
the prefix is "ABC". By defining the prefix as "ABC", we are
telling the library to use "ABC" as the first 3 characters of any
file that is created for the SAMPLEDB database.

The prefix can be from 1 to 4 characters in length. If a prefix is
not defined, a default prefix, "TEST", is used.

For more information about the CDB database file naming
conventions, refer to the 'Database File Names' section in this
manual.


connect

When using the connect keyword, you are taking advantage of the
network database model implementation of CDB. Network model
concepts can greatly increase the performance and efficiency of
your database.

The connect keyword defines a relationship between two records.

struct client
{
connectaddress key street;
.
.
};

In this example, we are defining a relationship between the client
record and the address record. The client record will be an owner
of the address record. The address record is a member of the
client record. For now, ignore the 'key street' part of the
connect phrase.

By declaring this set relationship, we now have the capability to
make connections between client and address records using the
DbSet... function calls. A client may own 0, 1 or many address
records. Without the network model concepts that we have just
shown you, to make connections between two records would require
the storage of a unique key in each individual record.

void Function()
{
static CLIENT client = {1000L,"Daytris","A software company",
0.00};
static ADDRESS address = {"81 Bright Street, Suite 1E",
"Jersey City","NJ","07302","201-200-0018",""};

DbRecordAdd( "client", &client);
DbRecordAdd( "address", &address);
DbSetAdd( "client", "address");
}


The example above shows how to make a set connection between two
records by using the DbSetAdd function. After the function call,
the client "Daytris" is the owner of 1 address record. This
address record can be retrieved using the DbSetGetFirst call:

DbSetGetFirst( "client", "address", &address);


Now lets add another address record to the set:

void Function()
{
long key = 1000L;
static ADDRESS address = {"30 Broad Street","New York","NY",
"10015","212-555-1212","212-555-1212"};

/* Make client #1000 current */
DbRecordFindByKey( "client", "clientnbr", &key);

/* Add another member */
DbRecordAdd( "address", &address);
DbSetAdd( "client", "address");
}

The client "Daytris" now owns 2 address records. We can use the
DbSetGetFirst, DbSetGetLast, DbSetGetNext, or DbSetGetPrev to
retrieve any of the address records in the set.

Now lets take a look at how the sets are ordered. If we make a
DbSetGetFirst call after adding the sets shown above, which address
record would be returned? Lets return to our original DDL example:

struct client
{
connectaddress key street;
.
.
};

Member records can be ordered two ways. By the order in which they
are added, or by a field in the member record. In our example, the
set order is by the street field in the address record. Therefore,
a DbSetGetFirst( "client", "address", ...) call would return the
"30 Broad Street" address record. If the connect address phrase
were defined without a key:

struct client
{
connectaddress;
.
.
};


the address members would be stored in the order that they were
added. Therefore, a DbSetGetFirst( "client", "address", ...)
call would return the "81 Bright Street, Suite 1E" address because
this address was added first.

A record can have more than one member. A record can also be owned
by more than one owner. To illustrate this, lets take the
SAMPLEDB.DDL and expand it to include invoicing capabilities.

/* sampledb.ddl - with invoicing */

prefix ABC;

struct client
{
connectaddress key street;
connectinvoice;
key longclientnbr;
key charname[31];
chardescription[61];
doublebalance;
};

struct address
{
charstreet[31];
charcity[21];
charstate[3];
key charzip[11];
key chartelephone[13];
charfax[13];
};

struct invoice
{
connect address;
connectinvoiceline;
key longinvoicenbr;
longdate;
doubletotalprice;
};

struct invoiceline
{
longquantity;
chardescription[31];
doubleunitprice;
doublelineprice;
};

struct setup
{
key longnextclientnbr;
longnextinvoicenbr;
};


In this example, a client record can own multiple address records
and multiple invoice records. This makes sense because a client
could have more than one address, i.e. a shipping and billing
address. The client could also have more than one invoice if more
than one order is placed.

Also in this example, an owner/member relationship exists between
the invoice and address records. If our invoice has both 'ship to'
and 'bill to' addresses, the shipping address could be stored as
the first member in the set and the billing address could be stored
as the next member.

A variable number of line items could exist on an invoice. This is
the reason for the invoiceline record and its relationship with the
invoice. An invoice record will own its invoice lines.

The following example illustrates how all data pertaining to a
specific invoice might be retrieved. Note: it is suggested that
the CDB return values be taken more seriously than illustrated
below.

typedef struct invoice INVOICE;
typedef struct invoiceline INVOICELINE
typedef struct client CLIENT;
typedef struct address ADDRESS;


void Function()
{
long key = 2000L;
UINT status;
INVOICE invoice;
INVOICELINE invoiceline;
CLIENT client;
ADDRESS shipaddress;
ADDRESS billaddress;

/* Get invoice #2000 */
DbRecordGetByKey( "invoice", "invoicenbr", &invoice, &key);

/* Get the client that owns the invoice */
DbSetGetOwner( "client", "invoice", &client);

/* Get the 'ship to' and 'bill to' addresses */
DbSetGetFirst( "invoice", "address", &shipaddress);
DbSetGetNext( "invoice", "address", &billaddress);

/* Retrieve all invoice lines (assuming at least 1 line) */
status = DbSetGetFirst( "invoice", "invoiceline", &invoiceline);
while( status != E_NONEXT && status != E_NOTFOUND)
{
/* Store the line */

/* Get the next line */
status = DbSetGetNext( "invoice", "invoiceline",
&invoiceline);
}
}

This example illustrates some of the capabilities that you have
with set relationships. The possibilities are endless.


key

The key word is used for defining key fields in records and key
fields to be used in set relationships. See the connect section
directly preceding this section for more details about the key
fields in set relationships.

Key fields are stored in ascending order in slots on pages in a
key file. The key file is made up of a series of linked pages.

struct client
{
connectaddress key street;
key longclientnbr;
charname[31];
chardescription[61];
doublebalance;
};


This DDL structure definition contains only one key field,
"clientnbr". Therefore all pages in the corresponding key file
will contain will contain slots of sorted client numbers.

struct client
{
connectaddress key street;
key longclientnbr;
key charname[31];
chardescription[61];
doublebalance;
};

The DDL structure definition now contains two key fields,
"clientnbr" and "name". Therefore two types of key pages will
exist in the key file for this record type. Some pages will
contain slots of sorted client numbers and other pages will contain
slots of sorted client names. The data stored on the key file
pages is directly related to the number of key fields defined in
the DDL file.

To maximize the efficiency of your database, it is suggested that
you use as few key fields as possible. The maximum number of key
fields allowed in a record is defined as MAXKEY in DBMGR.H. It is
currently set to 8. See 'Modifying the Database Internals' section
for more information about MAXKEY.

If a structure is defined without a key field, the only way to
access a record of this type is with a set relationship. The
structure defined without a key field must be a member of another
record.

struct client
{
connectaddress key street;
key longclientnbr;
key charname[31];
chardescription[61];
doublebalance;
};

struct address
{
charstreet[31];
charcity[21];
charstate[3];
charzip[11];
chartelephone[13];
charfax[13];
};

In this example, the address record contains no key fields.
Therefore, the address record cannot be accessed using any
DbRecord... function calls because these functions require a key
field as a parameter. However, the address is a member of the
client record. Therefore, it could be accessed with the
DbSetGet... function calls, provided a relationship exists.


DDL Limitations

The Data Definition Language does not currently support the
definition of structures or unions defined from within a structure.
Example:

struct client
{
struct address addr;
key longclientnbr;
key charname[31];
chardescription[61];
doublebalance;
};

These deficiencies will be supported in a later release of CDB.
A way to get around this problem for now is to allocate enough
space as a char field for the structure or union that could not be
included. Example (assuming the address structure length is 92
bytes):

struct client
{
char addr[92];
key longclientnbr;
key charname[31];
chardescription[61];
doublebalance;
};

After DDLP compilation, modify the C header file output by DDLP to
include the proper structure definition.


DATABASE CURRENCY


What is Currency?

Currency refers to the record position in a database key file. It
is very similiar to the file pointer in an open file. For example,
when you first open a file using the C run-time library "open"
function, the file pointer points to the first byte in the file
(it could point to the last byte depending on how its opened).
After the file is open, you can seek to different positions in the
file and read or write data. The file pointer position is kept
internally by the operating system. You could think of this
position as the current position or "currency".

In CDB, the concepts are very similar. Each record structure
defined in a DDL will have an associated currency table when this
database is opened.


An Example:

/* sampledb.ddl */

prefix ABC;

struct client
{
connectaddress key street;
key longclientnbr;
key charname[31];
chardescription[61];
doublebalance;
};

struct address
{
charstreet[31];
charcity[21];
charstate[3];
key charzip[11];
key chartelephone[13];
charfax[13];
};

struct setup
{
key longnextclientnbr;
};


When this database is opened using DbOpen, 3 currency tables will
be initialized to zero. One for each record type: 'client',
'address', and 'setup'. The currency table contains the following
format:

struct currency_index
{
struct
{
UINTpage;
UINTslot;
} keydba[MAXKEY];/* Array of key dba's */
ULONGdatadba;/* Data database address */
};


keydba

The currency table consists of two parts; a key currency (keydba)
and a data record currency (datadba). A keydba exists for each
key defined in the record table. In the example defined above,
the 'client' record would use the first two keydba structures in
the currency_index table for key currency storage. Records that
do not have any keys defined would not make use of the keydba part
of the currency_index.

Lets say that we have three 'client' records in our database. The
contents of each are as follows:

Record 1:1000L,"Daytris","Software Development",0.00
Record 2:1001L,"Microsoft","Software Development",10000.00
Record 3:1002L,"CompuServe","Computer Services",100.00

When the database is opened, the currency_index for the 'client'
record, as well as all other records, is null. In other words,
"the client record does not have currency". If we were to issue a:

DbRecordFindNext( "client", "clientnbr");

at this time, an E_NONEXT return value would result. There is no
next record to find! However, if we were to issue a:

DbRecordFindFirst( "client", "clientnbr");

the return value would be 0 indicating a successful call. After
this call, the keydba structure within the currency_index for the
'client' record would contain the appropriate page and slot number
of the first record for the "clientnbr" index. In this case, the
keydba[0] structure within the 'client' currency_index would point
to client number 1000L, Daytris.

If we were to now issue a:

DbRecrordFindNext( "client", "clientnbr");

the keydba[0] structure within the 'client' currency_index would
point to the next client sorted by "lClientNbr". In our example,
it would point to 1001L, Microsoft.

Keep in mind that we are not retrieving any records, we are only
setting currency for the 'client' record type. If we would want
to retrieve a record, we would use the DbRecordGet... function
calls. Using the DbRecordFind... function calls we can essentially
"seek" to positions within the database based on any index field
within a record type.


datadba

The datadba field in the currency_index is used for "set" currency.
When we issue a DbSetFind.. function call, the datadba is used to
locate the current set record. The datadba field contains the
actual slot number of the current record. "Next" and "previous"
set pointers are stored at the beginning of each data slot in a
data file.


Differences Between Find and Get Function Calls

The DbRecordFind... and DbSetFind... function calls only set
currency for a specific record type. They do not retrieve records.
You may want to think of the Find function calls as performing the
same task as the C run-time lseek function. Essentially, we are
seeking to a position in the database.

If you wish to retrieve a record, use the DbRecordGet... or the
DbSetGet... function calls. Note: The DbRecordGet... and
DbSetGet... function calls call their Find counterparts first, and
then retrieve the current record. For example, the
DbRecordGetFirst function will perform a DbRecordFindFirst and then
a DbRecordGetCurrent function call.


Storing Currency Tables

You can retrieve a copy of the current currency_index for each
record defined in the DDL. Why would you want to do this?

Lets suppose that you have a database that contains hundreds of
'client' records. Your application must be able to display these
'client' records in a small window, but you don't have enough
memory to keep all of the 'client' records resident. Or it may
be a waste of memory to do so. This is where storing currency
tables becomes necessary.

As previously explained, each record type defined in a DDL has an
associated currency table. The contents of a currency table can
be retrieved or updated at any time. Therefore, in the example
explained above, we could retrieve a window of 'client' records
along with their associated currency_index tables. Example:


UINT GetWindowOfClients( BOOL bFirstTime)
{
register short i;
UINT status;
struct currency_index currency;

for( i=0 ; i {
/* Get the record */
if( bFirstTime)
{
bFirstTime = FALSE;
status = DbRecordGetFirst( "client", "clientnbr",
&client);
}
else
status = DbRecordGetNext( "client", "clientnbr",
&client);
if( status)
return status;

/* Get the currency table */
status = DbRecordGetCurrency( "client", ¤cy);

/* Put the record in a window and store along with it
the associated currency table */
}
}

After calling this routine, we have a window of 'client' records.
For each 'client' record we also have an associated currency table.
If the user were to select a specific 'client' in the window, we
could retrieve this 'client' with the following database calls:

DbRecordUpdCurrency( "client", ¤cy);
DbRecordGetCurrent( "client", "clientnbr", &client);

The "currency" structure passed in the DbRecordUpdCurrency call
represents the currency_index of the selected 'client' record.
Because we have a currency table stored for each 'client' record
in the window, we can retrieve any record in the window using
this method.


Deleting a current record

Beware when deleting a current record. If you are storing a
series of currency tables as we have done in the example explained
above, deleting a current record will invalidate currency tables
that followed this record. Suppose we have a window of 'client'
records:

Record 1:1010L,"ABC Corp.","Diskette Manufacturer",0.00
Record 2:1011L,"XYZ Corp.","Hard Drive Manufacturer",0.00
Record 3:1012L,"BYTE Magazine","Software Publication",0.00
Record 4:1013L,"Sharp","Electronics",0.00
Record 5:1014L,"Collins","Radio Electronics",0.00

We have also stored currency tables associated with each 'client'
record in the window.

If for example we delete Record 2, "XYZ Corp.", the currency
tables associated with Records 3, 4, and 5 will now be invalid.
Remember that currency tables contain the page and slot of a data
item. If a record is deleted, the key fields are removed from
their associated pages. The data (slots) on a key page are
compressed to be contiguous. Therefore, key fields stored after
the deleted record will be moved up 1 slot. Or possibly, if the
slot is the last slot on a page, the page will be removed entirely.

To avoid retaining invalid currency tables in memory after deleting
a record, currency tables should be re-retrieved after the deletion.
To do this, start the retrieval with the record before the deleted
record. In the example above, Record 2 is being deleted. After
the deletion, restore the Record 1 currency table (using
DbRecordUpdCurrency) and re-retrieve next records and corresponding
currency tables (using DbRecordGetCurrency) until the window is
full.


Updating a current record

An update, like the delete described above, can create similar
problems. This is only a problem if the key field that was used
for the retrieval of records is updated. In this case, the slots
could be rearranged in an order unknown to the calling application.
The only way to solve this problem, is to re-retrieve the records
and their associated currency tables from the beginning after the
update takes place.


DATABASE INTERNALS


Memory Requirements

CDB requires a very small amount of memory to operate. The
library allocates all memory required for data access and
manipulation during the DbOpen call. Memory is NOT allocated by
the database during the execution of any other database call.

CDB will consume approximately 45K of code and data space. A
portion of this space is allocated when a database is opened. A
variable amount of memory is also allocated and depends upon the
size of the DBD file. This space is used for DBD record, owner,
member, and field tables. To calculate the variable amount of
memory that will be required by a DBD, use the following formula:

DBD memory consumption = (number of records * 46) +
(number of owners * 4) + (number of members * 8) +
(number of fields * 40)

The DBDLIST utility included in this release will display the
number of records, owners, members, and fields in a DBD. As an
example, the SAMPLEDB.DBD displayed in this document will consume
only 590 bytes for the tables described above.


Database Files

Database records are organized in data and key files. Each record
type defined in the DDL will have an associated data file. If any
key fields exist in this record, the record type will also have a
key file. Key files have a .key extension while data files have a
.dat extension.


File Naming

/* sampledb.ddl */

prefix ABC;

struct client
{
connectaddress key street;
key longclientnbr;
key charname[31];
chardescription[61];
doublebalance;
};

struct address
{
charstreet[31];
charcity[21];
charstate[3];
key charzip[11];
key chartelephone[13];
charfax[13];
};

struct setup
{
key longnextclientnbr;
};

Key and data files are not created until the first record of a
specific record type is added. For example, when the first
'client' record is added to the database, a data and key file will
be created. The names used for the .DAT and .KEY file are derived
as follows:

sprintf( keyfile, "%s%4.4d", prefix, orderinDBD);
sprintf( datfile, "%s%4.4d", szPrefix, orderinDBD);

The prefix is the prefix defined in the DDL. In our example, the
prefix is "ABC". The orderinDBD is the record number in the
database definition (.DBD) file. When DDLP compiles the DDL into
DBD format, record tables are stored describing each record
structure definition. The record tables are stored in alphabetical
order in the DBD file. In our example, the record order in the DBD
is 'address', 'client', then 'setup'. Therefore, when the first
'client' record is added to the database, ABC0001.DAT and
ABC0001.KEY are created. When the first 'address' record is added,
ABC0000.DAT and ABC0000.KEY are created.

If a record definiton does not contain a key field, a key file is
not created for this record.


Key File Layout

Key files are organized as a series of pages. Pages contain a
series of slots. The slots contain the key data. Slots on a page
are in sorted order. A key file will contain pages of keys for a
specific record type. For example, in SAMPLEDB.DDL shown above,
the 'client' key file will contain pages of keys for the 'client'
record.

Some pages will contain client numbers and some pages will contain
client names. A page will not contain both client numbers and
client names.

The key file structures are listed below:

struct key_file_index
{
CHARname[12];/* Key file name */
UINTnextavailpage;/* Next available page */
UINTfirstdelpage;/* First page in the delete */
/* chain. */
UINTpagenbr[MAXKEY];/* Key 1st page index */
};

This structure is included at the beginning of every key file. It
contains necessary pointers for finding the next available page,
first deleted page in the delete chain, and the first page for
each key field defined in the record.

struct key_page_index
{
UINTprevpage;/* Previous page in sort tree */
UINTnextpage;/* Next page in sort tree */
UINTslotsused;/* Number of slots used on page */
UINTslotsize;/* Size of key slot */
UINTflags; /* Bit 0 - page is full */
};

This structure is included at the beginning of each page in the
key file. The slots in the key file consist of nothing but raw
key field data.


Data File Layout

Data files do not contain pages. They are organized as a series
of slots in a file. Pages are not needed here because data files
contain only record data. They are indexed by their respective
key files.

The data file structures are listed below:

struct data_file_index
{
CHARname[12];/* Data file name */
ULONGnextavailslot;/* Next available slot */
ULONGfirstdelslot;/* First slot in the delete */
/* chain. */
UINTslotsize;/* Size of data slot */
CHARfiller[10];
};

This structrure is included at the beginning of every data file.
It contains necessary pointers for finding the next available slot,
first deleted slot in the delete chain, and the data slot size.

struct data_slot_index
{
UINToffsettodata;/* Offset to actual data */
ULONGnextdel;/* DBA of next member in the */
/* delete chain. */
};

This structure is included at the beginning of each data slot. A
data slot also contains owner and/or member data if the record type
is an owner of or member of another record. The owner and member
pointer tables are not shown here. In summary, a data slot
contains a data_slot_index, owner data tables, member data table,
followed by the actual data record.


Modifying Internal Definitions

It is relatively easy to change some of the global definitions
used CDB. In some extreme cases, modification may be necessary.
This, of course, depends on your database model (data definition
file). Source code is required to make any of the changes to the
definitions listed below.

All definitions described are included in DBMGR.H.


#define NBRHANDLES 12

This value is the number of database files that can be open at
one time. A data file exists for every record defined in the DDL
if at least one record of that type has been added. If the DDL
structure definition contains one or more key fields, a key file
will also be created.

struct client
{
key longlClientNbr;
key charszName[31];
charszDescription[61];
doubledBalance;
};

In this DDL example, two files will be created when the first
record of this type is added to the database. A data file will
be created and because at least 1 key field exists, a key file
will also be created.

CDB uses an LRU (least recently used) algorithm to manage
database file handles. If CDB needs to open a file and 12
database files are already open, CDB closes the least recently
used handle and proceeds to open the new file. The new file
handle is then placed in the LRU table.

If your database model contains more than 12 database files,
database perfomance may be enhanced by increasing the NBRHANDLES
value. Note: The maximum number of file handles available for a
single task under DOS is 20. 5 are reserved for internal use.
If you leave NBRHANDLES defined as 12, only 3 are available for
your application.


#define MAXKEY 8

This value is the maximum number of key fields that a single
record definition can contain. Increase this value only if you
have more than 8 key fields defined in a single record definition.


#define KEYPAGESIZE 512

Key fields are stored in sorted order in slots on pages. A key
file is made up of a header and a series of these pages.
KEYPAGESIZE is the size of a key page. If your database key
fields are very large, you might increase the performance of the
database by increasing this value. If modified, KEYPAGESIZE
should be a multiple of the average key field length. Note:
The larger the key page size, the longer the access time for
reads and writes.


#define NBRPAGES 16

This value is the number of key pages that are buffered in RAM
by CDB. These buffers are managed using an LRU (least recently
used) algorithm for maximum efficiency.


#define DATAPAGESIZE 2048

Data records are stored in slots on pages. The pages are stored
in the data file (.DAT). This value is the size of the data pages.
It is recommended that this value be a power of 2.


#define DATASLOTSIZE 1024

This value is the maximum size of a data slot. A data slot
contains a small header, followed by owner tables (if any),
followed by member tables (if any), followed by the actual data.
You will need to increase this value if your record sizes, when
plugged into the formula below, exceed 1024.

Formula:

6 +
(number of member record types this record can own * 8) +
(number of owner record types that can own this record * 12) +
C structure length (in bytes)

If you have very large C structures you should check them. It is
recommended that DATASLOTSIZE be a power of 2.


Example:

/* sampledb.ddl */

struct client
{
connectaddress key street;
key longclientnbr;
key charname[31];
chardescription[61];
doublebalance;
};

struct address
{
charstreet[31];
charcity[21];
charstate[3];
key charzip[11];
key chartelephone[13];
charfax[13];
};

In this DDL example, the size of a 'client' data slot would be:

6 +
(1 * 8) +
(0 * 12) +
104 = 118

The size of an 'address' data slot would be:

6 +
(0 * 8) +
(1 * 12) +
92 = 110


UTILITIES


DDLP.EXE

DDLP is the Data Definition Language Parser (compiler). It reads
the DDL file and creates a binary database definition file with a
.DBD extenstion. DDLP also creates a C header file with a .H
extension.

The DBD file name is used with the DbOpen function call. The
DbOpen function passes the DBD file name as a parameter. The DBD
file is read into memory by CDB and serves as a roadmap for the
database.

The maximum size of a .DDL file that DDLP can process is 65535
bytes. A complete list of DDLP error messages are provided in the
'Error Messages' section in this manual.


Syntax:

DDLP filename(.ddl)


Example:

DDLP sampledb.ddl

In this example, DDLP will create SAMPLEDB.DBD and SAMPLEDB.H if
the compilation is successful.


DBDLIST.EXE

DBDLIST displays the contents of the binary database definition
file (.DBD) created by DDLP. A header, record definitions, owner
definitions, member definitions, and field definitions are
displayed.

DBDLIST does not display the contents of any data or key files.


Syntax:

DBDLIST filename.dbd


Example:

DBDLIST sampledb.dbd


USING THE C-API


Introduction

The CDB C-API library is callable from both C and C++ modules.
Over 30 functions are available. Function prototypes are defined
in DBMGR.H.


Functions by Category

Database Management

DbClose Close a database.
DbFlush Flush all data files to disk.
DbOpen Open a database.


Record Management

DbRecordAddAdd a record.
DbRecordDelete Delete a record.
DbRecordUpdate Update a record.


Record Find

DbRecordFindByKeyFind a record by key value.
DbRecordFindFirstFind the first record.
DbRecordFindLastFind the last record.
DbRecordFindNextFind the next record.
DbRecordFindPrevFind the previous record.


Record Retrieval

DbRecordGetByKeyGet a record by key value.
DbRecordGetCurrentGet the current record.
DbRecordGetFirstGet the first record.
DbRecordGetLast Get the last record.
DbRecordGetNext Get the next record.
DbRecordGetPrev Get the previous record.


Record Currency

DbRecordGetCurrencyGet the currency table of a record type.
DbRecordUpdCurrencyUpdate the currency table of a record type.


Set Management

DbSetAddMake a set connection between two records.
DbSetDeleteRemove a set connection between two records.


Set Find

DbSetFindFirstFind the first member record in an
owner/member relationship.
DbSetFindLastFind the last member record in an
owner/member relationship.
DbSetFindNextFind the next member record in an
owner/member relationship.
DbSetFindPrevFind the previous member record in an
owner/member relationship.


Set Retrieval

DbSetGetFirstGet the first member record in an
owner/member relationship.
DbSetGetLastGet the last member record in an
owner/member relationship.
DbSetGetNextGet the next member record in an
owner/member relationship.
DbSetGetOwner Get the owner record of a member in an
owner/member relationship.
DbSetGetPrevGet the previous member record in an
owner/member relationship.


DbClose
-------

Summary

INT DbClose( void);


Description

The DbClose function closes the open database. All database
files are closed and memory is deallocated.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS. See the 'Error Messages' section for more detail
on this value.


Example

#include "dbmgr.h"

void Function()
{
INT status;

if( status = DbOpen( ".\\", "test.dbd"))
{
/* Database not opened */
}

/* Other CDB calls... */

if( status = DbClose())
{
/* Database not closed */
}
}


DbFlush
-------

Summary

INT DbFlush();


Description

The DbFlush function forces all data written to the database to
disk. Dirty memory pages are written to disk and all open files
are closed and then reopened.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS. See the 'Error Messages' section for more detail
on this value.


Example

#include "dbmgr.h"

void Function( struct client far *pClient)
{
INT status;

if( status = DbRecordUpdate( "client", pClient))
{
/* Record not updated */
}

if( status = DbFlush())
{
/* Database not flushed */
}
}


DbOpen
------

Summary

INT DbOpen( char *pDbDir, char *pDbName)


Parameters

pDbDir CHAR * Identifies the directory where CDB will
attempt to open the .DBD (Database Definition)
file. CDB will also attempt to open and/or create
all associated database files in this directory.
If NULL, CDB will use the current directory.
Note: If a directory name is present, it must
end with a backslash. e.g. "C:\\PRODUCTA\\".

pDbName CHAR * Identifies the .DBD (Database Definition)
file.


Description

The DbOpen function opens a CDB database. The database definition
file (pDbName) is created by DDLP.EXE.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS. See the 'Error Messages' section for more detail
on this value.


Example

#include "dbmgr.h"

void Function()
{
INT status;

if( status = DbOpen( "C:\\PRODUCTA\\", "test.dbd"))
{
/* Error opening database */
}

/* Other CDB calls... */
}


DbRecordAdd
-----------

Summary

INT DbRecordAdd( CHAR *pRecName, VOID *pData)


Parameters

pRecNameCHAR * Pointer to the record name.

pData VOID * Pointer to the record data.


Description

The DbRecordAdd function adds a record to the database.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS or E_NORECNAME. See the 'Error Messages' section
for more detail on these values.


Example

#include "dbmgr.h"

INT Function( CHAR *pClientData)
{
INT status;

if( status = DbRecordAdd( "client", pClientData))
{
/* Error adding record */
}

return status;
}


DbRecordDelete
--------------

Summary

INT DbRecordDelete( CHAR *pRecName)


Parameters

pRecName CHAR * Pointer to the record name.


Description

The DbRecordDelete function deletes a record from the database.
The record deleted is the current record of the pRecName type.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, or E_NOCURRENT. See the 'Error
Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;

if( status = DbRecordFindByKey( "client", "clientnbr",
&clientnbr))
{
/* Record not found */
}

if( status = DbRecordDelete( "client"))
{
/* Error deleting record */
}
}


DbRecordFindByKey
-----------------

Summary

INT DbRecordFindByKey( CHAR *pRecName, CHAR *pFldName, VOID *pKey)


Parameters

pRecNameCHAR * Pointer to the record name.

pFldNameCHAR * Pointer to the field name. Must be a key
field.

pKey VOID * Pointer to the key data to be used for the
record search.


Description

The DbRecordFindByKey function searches for a specific record
using a key field and key value.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND, or
E_NEXTGUESS. See the 'Error Messages' section for more detail on
these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;

if( status = DbRecordFindByKey( "client", "lClientNbr",
&clientnbr))
{
/* Record not found */
}
}


DbRecordFindFirst
-----------------

Summary

INT DbRecordFindFirst( CHAR *pRecName, CHAR *pFldName)


Parameters

pRecNameCHAR * Pointer to the record name.

pFldNameCHAR * Pointer to the field name. Must be a key
field.


Description

The DbRecordFindFirst function sets the database currency to the
first logical record sorted by pFldName. For more on currency,
see the Database Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, or E_NOTFOUND.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;

/* Delete all client records in database */
while( ! DbRecordFindFirst( "client", "clientnbr"))
{
if( status = DbRecordDelete( "client"))
{
/* Error deleting record */
}
}
}


DbRecordFindLast
----------------

Summary

INT DbRecordFindLast( CHAR *pRecName, CHAR *pFldName)


Parameters

pRecNameCHAR * Pointer to the record name.

pFldNameCHAR * Pointer to the field name. Must be a key
field.


Description

The DbRecordFindLast function sets the database currency to the
last logical record sorted by pFldName. For more on currency, see
the Database Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, or E_NOTFOUND.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;

/* Delete all client records in database */
while( ! DbRecordFindLast( "client", "clientnbr"))
{
if( status = DbRecordDelete( "client"))
{
/* Error deleting record */
}
}
}


DbRecordFindNext
----------------

Summary

INT DbRecordFindNext( CHAR *pRecName, CHAR *pFldName)


Parameters

pRecNameCHAR * Pointer to the record name.

pFldNameCHAR * Pointer to the field name. Must be a key
field.


Description

The DbRecordFindNext function sets the database currency to the
next logical record sorted by pFldName. The record must have
currency before this call is executed. For more on currency, see
the Database Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND,
E_NOCURRENT, or E_NONEXT. See the 'Error Messages' section for
more detail on these values.


Example

#include "dbmgr.h"

INT Function()
{
/* Down arrow key pressed, check for next */
/* record in database. */
return( DbRecordFindNext( "client", "clientnbr"));
}


DbRecordFindPrev
----------------

Summary

INT DbRecordFindPrev( CHAR *pRecName, CHAR *pFldName)


Parameters

pRecNameCHAR * Pointer to the record name.

pFldNameCHAR * Pointer to the field name. Must be a key
field.


Description

The DbRecordFindPrev function sets the database currency to the
previous logical record sorted by pFldName. The record must have
currency before this call is executed. For more on currency, see
the Database Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND,
E_NOCURRENT, or E_NOPREV. See the 'Error Messages' section for
more detail on these values.


Example

#include "dbmgr.h"

INT Function()
{
/* Up arrow key pressed, check for previous */
/* record in database. */
return( DbRecordFindPrev( "client", "clientnbr"));
}


DbRecordGetByKey
----------------

Summary

INT DbRecordGetByKey( CHAR *pRecName, CHAR *pFldName, VOID *pTarget,
VOID * pKey)


Parameters

pRecNameCHAR * Pointer to the record name.

pFldNameCHAR * Pointer to the field name. Must be a key
field.

pTarget VOID * Pointer to the storage area for the record
data.

pKey VOID * Pointer to the key data.


Description

The DbRecordGetByKey function retrieves a record using a key value.
If the exact match cannot be found the function will return
E_NEXTGUESS specifying that the data returned is the next best
guess.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND, or
E_NEXTGUESS. See the 'Error Messages' section for more detail on
these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG key = 1000L;
CLIENT client;

/* Get client record with client number equal 1000L */
if( status = DbRecordGetByKey( "client", "clientnbr", &client,
&key))
{
/* Client not retrieved */
}
}


DbRecordGetCurrency
-------------------

Summary

INT DbRecordGetCurrency( CHAR *pRecName, VOID *pTarget)


Parameters

pRecNameCHAR * Pointer to the record name.

pTarget VOID * Pointer to the storage area for the currency
information.


Description

The DbRecordGetCurrency function retrieves the current currency
table for a specific record. For more on currency, see the
Database Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, or E_NORECNAME. See the 'Error Messages' section for
more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
struct currency_index currency;

/* Get the currency for the client record */
if( status = DbRecordGetCurrency( "client", ¤cy))
{
/* Currency not retrieved */
}

/* Other processing goes here... */

/* Restore the currency for the client record */
if( status = DbRecordUpdCurrency( "client", ¤cy))
{
/* Currency not updated */
}
}


DbRecordGetCurrent
------------------

Summary

INT DbRecordGetCurrent( CHAR *pRecName, VOID *pTarget)


Parameters

pRecNameCHAR * Pointer to the record name.

pTarget VOID * Pointer to the storage area for the record
data.


Description

The DbRecordGetCurrent function retrieves the record that has
currency (or 'is current') for that record type (record name).
Each record type has its own currency table. For more on currency,
see the Database Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, or E_NOCURRENT. See the 'Error Messages'
section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;
CLIENT client;

/* Check for client #1000 */
if( status = DbRecordFindByKey( "client", "lClientNbr",
&clientnbr))
{
/* Record not found */
}

/* Retrieve it */
if( status = DbRecordGetCurrent( "client", &client))
{
/* Record not retrieved */
}
}


DbRecordGetFirst
----------------

Summary

INT DbRecordGetFirst( CHAR *pRecName, CHAR *pFldName, VOID *pTarget)


Parameters

pRecNameCHAR * Pointer to the record name.

pFldNameCHAR * Pointer to the field name. Must be a key
field.

pTarget VOID * Pointer to the storage area for the record
data.


Description

The DbRecordGetFirst function retrieves the first record by the
key field passed. After this call, the currency for this record
type is set to the first record.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, or E_NOTFOUND.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
CLIENT client;

/* Get the first record sorted by client number*/
if( status = DbRecordGetFirst( "client", "clientnbr", &client))
{
/* Record not retrieved */
}
}


DbRecordGetLast
---------------

Summary

INT DbRecordGetLast( CHAR *pRecName, CHAR *pFldName, VOID *pTarget)


Parameters

pRecNameCHAR * Pointer to the record name.

pFldNameCHAR * Pointer to the field name. Must be a key
field.

pTarget VOID * Pointer to the storage area for the record
data.


Description

The DbRecordGetLast function retrieves the last record by the key
field passed. After this call, the currency for this record type
is set to the last record.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, or E_NOTFOUND.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
CLIENT client;


/* Get the last record sorted by client number*/
if( status = DbRecordGetLast( "client", "clientnbr", &client))
{
/* Record not retrieved */
}
}


DbRecordGetNext
---------------

Summary

INT DbRecordGetNext( CHAR *pRecName, CHAR *pFldName, VOID *pTarget)


Parameters

pRecNameCHAR * Pointer to the record name.

pFldNameCHAR * Pointer to the field name. Must be a key
field.

pTarget VOID * Pointer to the storage area for the record
data.


Description

The DbRecordGetNext function retrieves the next record by the key
field passed. After this call, the currency for this record type
is set to the record retrieved.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND,
E_NOCURRENT, or E_NONEXT. See the 'Error Messages' section for
more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
CLIENT client;

/* Get the next record sorted by client number*/
if( status = DbRecordGetNext( "client", "clientnbr", &client))
{
/* Record not retrieved */
}
}


DbRecordGetPrev
---------------

Summary

INT DbRecordGetPrev( CHAR *pRecName, CHAR *pFldName, VOID *pTarget)


Parameters

pRecNameCHAR * Pointer to the record name.

pFldNameCHAR * Pointer to the field name. Must be a key
field.

pTarget VOID * Pointer to the storage area for the record
data.


Description

The DbRecordGetPrev function retrieves the previous record by the
key field passed. After this call, the currency for this record
type is set to the record retrieved.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND,
E_NOCURRENT, or E_NOPREV. See the 'Error Messages' section for
more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
CLIENT client;

/* Get the previous record sorted by client number*/
if( status = DbRecordGetPrev( "client", "clientnbr", &client))
{
/* Record not retrieved */
}
}


DbRecordUpdate
--------------

Summary

INT DbRecordUpdate( CHAR *pRecName, VOID *pData)


Parameters

pRecNameCHAR * Pointer to the record name.

pData VOID * Pointer to the updated record data.


Description

The DbRecordUpdate function updates a database record. The record
to be updated must be current. For more on currency, see the
Database Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, or E_NOCURRENT. See the 'Error Messages'
section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
CLIENT client;

/* Get the first record */
if( status = DbRecordGetFirst( "client", "clientnbr", &client))
{
/* Record not retrieved */
}

/* Modify input logic goes here... */

/* Update the record */
if( status = DbRecordUpdate( "client", &client))
{
/* Error updating record */
}
}


DbRecordUpdCurrency

-------------------

Summary

INT DbRecordUpdCurrency( CHAR *pRecName, VOID *pData)


Parameters

pRecNameCHAR * Pointer to the record name.

pData VOID * Pointer to the storage area for the currency
information.


Description

The DbRecordUpdCurrency function updates the currency for a
specific record type. For more on currency, see the Database
Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS or E_NORECNAME. See the 'Error Messages' section for
more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
struct currency_index currency;

/* Get the currency for the client record */
if( status = DbRecordGetCurrency( "client", ¤cy))
{
/* Error retrieving currency */
}

/* Other processing goes here... */

/* Restore the currency for the client record */
if( status = DbRecordUpdCurrency( "client", ¤cy))
{
/* Error updating currency */
}
}


DbSetAdd
--------

Summary

INT DbSetAdd( CHAR *pOwnerName, CHAR *pMemberName)


Parameters

pOwnerNameCHAR * Pointer to the owner record name.

pMemberNameCHAR * Pointer to the member record name.


Description

The DbSetAdd function makes a set connection between two records.
Both records must have currency before making the call.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_INVALIDSET, or E_NOCURRENT. See the
'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;

/* Add an client record */
/* Assuming 'sclient' is global and structure prefilled */
if( status = DbRecordAdd( "client", &sclient))
{
/* Error adding record */
}

/* Add an address record */
/* Assuming 'saddress' is global and structure prefilled */
if( status = DbRecordAdd( "address", &saddress))
{
/* Error adding record */
}

/* Make a set connection between records */
/* After this call, the 'client' record is the owner of the */
/* 'address' record */
/* The 'address' record is a member of the 'client' record */
if( status = DbSetAdd( "client", "address"))
{
/* Error making set connection */
}
}


DbSetDelete
-----------

Summary

INT DbSetDelete( CHAR *pOwnerName, CHAR *pMemberName)


Parameters

pOwnerNameCHAR * Pointer to the owner record name.

pMemberNameCHAR * Pointer to the member record name.


Description

The DbSetDelete function removes a set connection between two
records. Both records must have currency before making the call.
This function does not delete either record, it only removes the
connection between the two.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_INVALIDSET, or E_NOCURRENT. See the
'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;

/* Set the currency to client record #1000 */
if( status = DbRecordFindByKey( "client", "clientnbr",
&clientnbr))
{
/* Record not found */
}

/* Set the currency for the address record to the first */
/* member of the client record */
if( status = DbSetFindFirst( "client", "address"))
{
/* First member not found */
}

/* Delete the owner/member set connection */
if( status = DbSetDelete( "client", "address"))
{
/* Error deleting record */
}
}


DbSetFindFirst
--------------

Summary

INT DbSetFindFirst( CHAR *pOwnerName, CHAR *pMemberName)

Parameters

pOwnerNameCHAR * Pointer to the owner record name.

pMemberNameCHAR * Pointer to the member record name.


Description

The DbSetFindFirst function sets the database currency for the
member record to the first member in the owner/member set relation.
The owner record must have currency before this call. For more on
currency, see the Database Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOTFOUND.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;

/* Set the currency to client record #1000 */
if( status = DbRecordFindByKey( "client", "clientnbr",
&clientnbr))
{
/* Record not found */
}

/* Set the currency for the address record to the first */
/* member of the client record */
if( status = DbSetFindFirst( "client", "address"))
{
/* First member not found */
}
}


DbSetFindLast
-------------

Summary

INT DbSetFindLast( CHAR *pOwnerName, CHAR *pMemberName)


Parameters

pOwnerNameCHAR * Pointer to the owner record name.

pMemberNameCHAR * Pointer to the member record name.


Description

The DbSetFindLast function sets the database currency for the
member record to the last member in the owner/member set relation.
The owner record must have currency before this call. For more on
currency, see the Database Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOTFOUND.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;

/* Set the currency to client record #1000 */
if( status = DbRecordFindByKey( "client", "clientnbr",
&clientnbr))
{
/* Record not found */
}

/* Set the currency for the address record to the last */
/* member of the client record */
if( status = DbSetFindLast( "client", "address"))
{
/* Last member not found */
}
}


DbSetFindNext
-------------

Summary

INT DbSetFindNext( CHAR *pOwnerName, CHAR *pMemberName)


Parameters

pOwnerNameCHAR * Pointer to the owner record name.

pMemberNameCHAR * Pointer to the member record name.


Description

The DbSetFindNext function sets the database currency for the
member record to the next member in the owner/member set relation.
Both owner and member records must have currency before this call.
For more on currency, see the Database Currency section in this
manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NONEXT.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;

/* Set the currency to client record #1000 */
if( status = DbRecordFindByKey( "client", "clientnbr",
&clientnbr))
{
/* Record not found */
}

/* Set the currency for the address record to the first */
/* member of the client record */
if( status = DbSetFindFirst( "client", "address"))
{
/* First member not found */
}

/* Set the currency for the address record to the next member */
/* of the client record */
if( status = DbSetFindNext( "client", "address"))
{
/* Next member not found */
}
}


DbSetFindPrev
-------------

Summary

INT DbSetFindPrev( CHAR *pOwnerName, CHAR *pMemberName)


Parameters

pOwnerNameCHAR * Pointer to the owner record name.

pMemberNameCHAR * Pointer to the member record name.


Description

The DbSetFindPrev function sets the database currency for the
member record to the previous member in the owner/member set
relation. Both owner and member records must have currency
before this call. For more on currency, see the Database Currency
section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOPREV.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;

/* Set the currency to client record #1000 */
if( status = DbRecordFindByKey( "client", "clientnbr",
&clientnbr))
{
/* Record not found */
}

/* Set the currency for the address record to the last */
/* member of the client record */
if( status = DbSetFindLast( "client", "address"))
{
/* Last member not found */
}

/* Set the currency for the address record to the previous */
/* member of the client record */
if( status = DbSetFindPrev( "client", "address"))
{
/* Previous member not found */
}
}


DbSetGetFirst
-------------

Summary

INT DbSetGetFirst( CHAR *pOwnerName, CHAR *pMemberName,
VOID *pTarget)


Parameters

pOwnerNameCHAR * Pointer to the owner record name.

pMemberNameCHAR * Pointer to the member record name.

pTarget VOID * Pointer to the storage area for the record
data.


Description

The DbSetGetFirst function retrieves the first member of an
owner/member set relation. The owner record must have currency
before this call. For more on currency, see the Database Currency
section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOTFOUND.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;
ADDRESS address;

/* Set the currency to client record #1000 */
if( status = DbRecordFindByKey( "client", "clientnbr",
&clientnbr))
{
/* Record not found */
}

/* Get the first address record */
if( status = DbSetGetFirst( "client", "address", &address))
{
/* First member not found */
}
}


DbSetGetLast
------------

Summary

INT DbSetGetLast( CHAR *pOwnerName, CHAR *pMemberName, VOID *pTarget)


Parameters

pOwnerNameCHAR * Pointer to the owner record name.

pMemberNameCHAR * Pointer to the member record name.

pTarget VOID * Pointer to the storage area for the record
data.


Description

The DbSetGetLast function retrieves the last member of an
owner/member set relation. The owner record must have currency
before this call. For more on currency, see the Database Currency
section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOTFOUND.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;
ADDRESS address;

/* Set the currency to client record #1000 */
if( status = DbRecordFindByKey( "client", "clientnbr",
&clientnbr))
{
/* Record not found */
}

/* Get the last address record */
if( status = DbSetGetLast( "client", "address", &address))
{
/* Last member not found */
}
}


DbSetGetNext
------------

Summary

INT DbSetGetNext( CHAR *pOwnerName, CHAR *pMemberName, VOID *pTarget)


Parameters

pOwnerNameCHAR * Pointer to the owner record name.

pMemberNameCHAR * Pointer to the member record name.

pTarget VOID * Pointer to the storage area for the record
data.


Description

The DbSetGetNext function retrieves the next member of an
owner/member set relation. Both owner and member records must
have currency before this call. For more on currency, see the
Database Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NONEXT.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;
ADDRESS address;

/* Set the currency to client record #1000 */
if( status = DbRecordFindByKey( "client", "clientnbr",
&clientnbr))
{
/* Record not found */
}

/* Get the first address record */
if( status = DbSetGetFirst( "client", "address", &address))
{
/* First member not found */
}

/* Get the next address record */
if( status = DbSetGetNext( "client", "address", &address))
{
/* Next member not found */
}
}


DbSetGetOwner
-------------

Summary

INT DbSetGetOwner( CHAR *pOwnerName, CHAR *pMemberName,
VOID *pTarget)


Parameters

pOwnerNameCHAR * Pointer to the owner record name.

pMemberNameCHAR * Pointer to the member record name.

pTarget VOID * Pointer to the storage area for the record
data.


Description

The DbSetGetOwner function retrieves the owner record of a member
record set relation. The member record must have currency before
this call. For more on currency, see the Database Currency section
in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOOWNER.
See the 'Error Messages' section for more detail on these values.


Example

#include "dbmgr.h"

void Function()
{
INT status;
CLIENT client;

/* Set the currency to the first invoice record */
if( status = DbRecordFindFirst( "invoice", "invoicenbr"))
{
/* Invoice not found */
}

/* Get the client record for this invoice */
if( status = DbSetGetOwner( "client", "invoice", &client))
{
/* Client record not found */
}
}


DbSetGetPrev
------------

Summary

INT DbSetGetPrev( CHAR *pOwnerName, CHAR *pMemberName, VOID *pTarget)


Parameters

pOwnerNameCHAR * Pointer to the owner record name.

pMemberNameCHAR * Pointer to the member record name.

pTarget VOID * Pointer to the storage area for the record
data.


Description

The DbSetGetPrev function retrieves the previous member of an
owner/member set relation. Both owner and member records must
have currency before this call. For more on currency, see the
Database Currency section in this manual.


Return Value

A 0 is returned if no error occurred. Otherwise the return code
can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOPREV.
See the 'Error Messages' section for more detail on these values.


Example


#include "dbmgr.h"

void Function()
{
INT status;
LONG clientnbr = 1000L;
ADDRESS address;

/* Set the currency to client record #1000 */
if( status = DbRecordFindByKey( "client", "clientnbr",
&clientnbr))
{
/* Record not found */
}

/* Get the last address record */
if( status = DbSetGetLast( "client", "address", &address))
{
/* Last member not found */
}

/* Get the previous address record */
if( status = DbSetGetPrev( "client", "address", &address))
{
/* Previous member not found */
}
}


ERROR MESSAGES

This section describes error messages that you may encounter when
developing a program using CDB.


CDB Run-Time Error Messages

The CDB C-API function calls return an INT value indicating the
success or failure of a particular database call. A 0 is returned
if the function was a success. A non-zero value is returned if an
error occured.

The following list displays the possible error codes that can be
returned and a brief explanation of each.


Error CodeDescription

E_TESTDRIVEYou are using a 'Test Drive' version of CDB.
The 'Test Drive' version limits the number
of records that can be added to a database
to 50.

E_INVALIDCASE Contact Daytris technical support. An
internal switch statement does not contain
a valid case. You should never see this
error code.

E_DOS An MS-DOS error has occured. The global
'errno' value contains the specific DOS
error number. See ERRNO.H and/or the
Microsoft C documentation for more
information.

E_NORECNAME The record name passed, pRecName, is not a
valid record type.

E_NOFLDNAME The field name passed, pFldName, is not a
valid field for the record.

E_INVALIDSET The owner and member names passed to the
function do not have a set relationship
between the two. To create a set
relatiionship between two records, use the
CONNECT keyword in the DDL file.

E_NOTAKEY The field name passed to the function is
not a key field in the record. Use the KEY
keyword in the DDL file to define key
fields.

E_NOTFOUND The record was not found.


E_NEXTGUESSThe record was not found, but the next
closest match to the key value passed was
found. If a DbRecordFindByKey call was
made, currency is set to this 'next guess'
record. If a DbRecordGetByKey call was
made, the 'next guess' record is returned.

E_NOCURRENT There is no current record for the record
name specified. e.g. This error value
will be returned if a DbRecordGetNext call
is made before the record requested has
currency. One way to set currency in this
case would be to make a DbRecordFindFirst
call. There are a number of other cases
where this error code could be returned.

E_NONEXTThe next record was not found. e.g.
DbRecordGetNext(...).

E_NOPREVThe previous record was not found. e.g.
DbRecordGetPrevious(...).

E_NOOWNERThis error can only occur with a
DbSetGetOwner call. If an owner record is
not found, this value is returned.


DDLP Error Messages

The following lists contain a description of error and warning
messages that may be encountered during the execution of the Data
Definition Language Parse utility (DDLP.EXE):

Error NumberDescription

100Unexpected end of file reached.
101Unexpected token. DDLP breaks the DDL file into
tokens. A token can be a bracket, keyword,
semicolon, variable, constant, etc. It combines the
tokens and matches them against predefined patterns.
If a pattern has no match, this error is returned.
102Expecting semicolon.
103Expecting "struct" keyword. DDLP is expecting a
structure definition to begin.
104Expecting identifier. An identifer can be a
structure name or field name.
105Expecting '{'. Expecting a left brace.
106Constant too big. A constant is a number. The
maximum constant size allowed is 10 digits.
107Structure already defined.
108Invalid constant. The interpreted value of the
constant is zero.
109Maximum size of a constant is 65535.
110Maximum size of a field is 65535.
111Maximum size of a record is 65535.
112Connection already made to 'record name'. You
cannot to the same record more than once.
113Record does not exist. This error will occur when
you try to CONNECT to a record that is not defined
within the DDL file.
114Cannot connect structure to itself.
115Connect key field not found. If you are ordering
the sets using the 'CONNECT record_name KEY
key_field_name' convention, the key_field_name is
not found within the record_name structure
definition in the DDL file.

Warning NumberDescription

100"prefix" not defined, assuming "test". The PREFIX
keyword was not used to define the prefix used to
derive database file names. A "test" prefix is
used as a default.
101Prefix too long, truncating to 'identifier'. The
maximum length of a PREFIX is 5 characters.
102Identifier too long. The maximum length of an
identifier is 31 characters. Extra characters will
be truncated.


 December 7, 2017  Add comments

Leave a Reply