Working with Databases

A database is a collection of tables and a session may contain several different databases. A database object is required before any table or data operations may take place. The following are typical operations performed on a database:

  • Create a database object
  • Connect to a database by calling CTDatabase::Connect()
  • Perform table, index, field and record operations
  • When you are done with the database, disconnect by calling CTDatabase::Disconnect()
  • Destroy the database object if it was created with the new operator

Creating a Database object

A valid database object is required to perform any database operation. You need to pass a valid CTSession object to the CTDatabase constructor.

// create a CTDatabase object
CTDatabase ADatabase(ASession);
try
{
// connect to database "MyDatabase"
ADatabase.Connect("MyDatabase");
}
catch (CTException &err)
{
printf("Database connect failed with error %d\n", err.GetErrorCode);
}

If you create a dynamic CTDatabase object with the new operator, you are required to destroy the object with the delete operator.

// create a dynamic CTDatabase object
CTDatabase* pDatabase = new CTDatabase(ASession);
 
if (!pDatabase)
{
   printf("CTDatabase creating failed\n");
}  
... other operations ..
// destroy the CTDatabase object
delete pDatabase;

If you destroy an active database handle, all open tables associated with the database will be closed and the database will be disconnected from the session.

Connecting to a database

Before performing any operations with a database, a database object must be connected to a session by calling CTDatabase::Connect() method. The database should already have been created or added to the session.

// connect to a database
CTDatabase ADatabase(ASession);
 
try
{
ADatabase.Connect("MyDatabase");
}
catch (CTException &err)
{
   printf("Connect to database failed with error %d\n", err.GetErrorCode());
}

When a database is connected to the session, it is considered "active". Use CTDatabase::IsActive() to check if a particular database is active.

When the database connection is no longer needed, it must be disconnected from the session by calling CTDatabase::Disconnect() method.

// disconnect from a database
try
{
   ADatabase.Disconnect();
}
catch (CTException &err)
{
   printf("Disconnect from database failed with error %d\n",
          err.GetErrorCode());
}

Database properties

The default database properties are suitable for most FairCom DB API applications. Advanced developers may need to tune FairCom DB API to meet application requirements.

Database name

Once the database object connects, retrieve the database name with CTDatabase::GetName().

// display the database name
printf("Database: %s\n", ADatabase.GetName().c_str());

Database path

The database path, by default, is the server directory for client/server applications, or the application directory for non-server applications. To set a different database path, when the database is being created, just insert the appropriate path as the second parameter of CTSession::CreateDatabase(). With this information stored in the Session dictionary, the user does not need to know where it is located, since it will be automatically retrieved given the database name.

Once the database is successfully connected to a session, obtain the database path with CTDatabase::GetPath().

// display database properties
void DisplayDatabaseProperties(CTDatabase &ADatabase)
{
   printf("Database: %s\n", ADatabase.GetName().c_str());
   printf("Path: %s\n", ADatabase.GetPath().c_str());
   printf("Number of tables: %d\n", ADatabase.GetTableCount());
}

Table count

CTDatabase::GetTableCount() retrieves the number of tables associated with a database. CTDatabase::GetTableCount() return -1 (minus 1) if the database is not connected or if the database object is invalid.

// display the number of tables in database
printf("Number of tables: %d\n", ADatabase.GetTableCount());

Managing Tables

Once the user performs a successful database connect, the database handle can be used to operate on tables.

Every time a new table is created, or an existing table is added to a database, some of the table properties such as table name, path, data file extension, index file extension, etc, are placed in an entry of the database dictionary file.

Every time a user activates a table by opening it with CTTable::Open() method, the table is placed in a list of active (opened) tables within the database. When a table is deactivated, or closed by calling CTTable::Close() method, the table is removed from the list of active tables in the database. A user may query the active table list by locating the first active table, the next active table and finding a specific active table.

Adding an existing table

An existing table may be added or imported to a database by calling the CTDatabase::AddTable() method. CTDatabase:AddTable() takes as parameters the table name and the table path.

// add MyTable to the current database
try
{
   ADatabase.AddTable("MyTable", "");
}
catch (CTException &err)
{
   printf("Add table failed with error %d\n", err.GetErrorCode());
}

Adding an existing table under transaction control

An extra level of data integrity can be achieved when you add an existing table to a database under transaction control. When the transaction is committed, the database dictionary data for the table is committed to disk. If the transaction is aborted, the dictionary data for the table is automatically removed from the database dictionary.

The code fragment below shows how to add an existing table under transaction control.

// begin a transaction
ADatabase.Begin();
try
{
   // add MyTable to the current database
   ADatabase.AddTable("MyTable", "");
   // commit the transaction
   ADatabase.Commit();
}
catch (CTException &err)
{
   // abort the transaction
   ADatabase.Abort();
   printf("Add table failed with code %d\n", err.GetErrorCode());
}

Dropping a table

When you drop a table from a database, the table information is removed from the database dictionary, but the table data and index files are left untouched. The drop table operation can be reversed with an add table operation. Drop a table from a database by calling CTDatabase::DropTable() method.

// drop MyTable from current database
try
{
   ADatabase.DropTable("MyTable");
}
catch (CTException &err)
{
   printf("Drop table failed with code %d\n", err.GetErrorCode());
}

Dropping a table under transaction control

An extra level of data integrity can be achieved when you drop a table from a database under transaction control. When the transaction is committed, the changes to the database dictionary data for the table are committed to disk. If the transaction is aborted, the dictionary data for the table is automatically restored to the database dictionary.

The code fragment below shows how to drop an existing table under transaction control. No error checking is included in the sample code:

// start a transaction
ADatabase.Begin();
try
{
   // drop MyTable from current database
   ADatabase.DropTable("MyTable");
   // commit the transaction
   ADatabase.Commit();
}
catch (CTException &err)
{
   // abort the transaction
   ADatabase.Abort();
   printf("Drop table failed with code %d\n", err.GetErrorCode());
}

Deleting a table

When you delete a table from a database, the table information is removed from the database dictionary and the table data and index files are deleted from disk. The delete table operation can be reversed only when used under transaction control. Without transaction control, a delete table operation will delete the data and index files and the table data will be lost. Delete a table from a database by calling CTDatabase::DeleteTable() method. Example:

// delete MyTable from current database
try
{
CTString password;
ADatabase.DeleteTable("MyTable", password);
}
catch (CTException &err)
{
   printf("Delete table failed with code %d\n", err.GetErrorCode());
}

Note: The DeleteTable() method takes as parameters the table name and the table password. Set the password parameter to an empty CTString object if a table was created without passwords.

Deleting a table under transaction control

An extra level of data integrity can be achieved when you delete a table from a database under transaction control. When the transaction is committed, the changes to the database dictionary data for the table are committed to disk and the table and index files are deleted from disk. If the transaction is aborted, the dictionary data for the table is automatically restored to the database dictionary and the original data and index files are restored to their original state.

The code fragment below shows how to delete an existing table under transaction control. No error checking is included in the sample code:

// start a transaction
try
{
  // delete MyTable from current database
  CTString password;
  ADatabase.DeleteTable("MyTable", password);
  
  // commit the transaction
  ADatabase.Commit();
}
catch (CTException &err) 
{
   // abort the transaction
   ADatabase.Abort();
   printf("Delete table failed with code %d\n", err.GetErrorCode());
}

First Table

CTDatabase::FirstTable() retrieves the name and path of the first table in a session. If the session has no tables, CTDatabase::FirstTable() returns NO (false). See the example in "Next Table".

 

Next Table

CTDatabase::NextTable() retrieves the name and path of the next table in a database. CTDatabase::NextTable() returns NO (false) when no more tables exist for the current database.

// Display all tables in a database
void DisplayTables(CTDatabase &ADatabase)
{
CTString Name;
CTString Path;
 
if (ADatabase.FirstTable(Name, Path))
do
{
   printf("Table: %s Path: %s\n", Name.c_str(), Path.c_str());
}
while (ADatabase.NextTable(Name, Path);
}

Find Table

CTDatabase::FindTable() locates a specific table given the table name and, if the table exists, retrieves the table path. If a table cannot be found, CTDatabase::FindTable() returns NO (false).

// return YES if table exist or NO if table does not exit
CTBOOL TableExist(CTDatabase &ADatabase, CTString& tblName)
{
   CTString tblPath;
 
   return ADatabase.FindTable(TblName, tblPath);
}

First Active Table

CTDatabase::GetFirstActive() retrieves the table object pointer of the first active table. If the database contains no active tables, CTDatabase::GetFirstActive() returns NULL.

Next Active Table

CTDatabase::GetNextActive() retrieves the table object pointer of the next active table. When no more active tables exist, CTDatabase::GetNextActive() returns NULL.

// Display all active tables
void DisplayActiveTables(CTDatabase &ADatabase)
{
   VRLEN hScan;
   CTTable *pTable;
 
   if ((pTable = ADatabase.GetFirstActive(&hScan)) != NULL)
   {
      do
      {
         printf("Table: %s Path: %s\n", pTable->GetName().c_str(),
         pTable->GetPath().c_str());
         pTable = ADatabase.GetNextActive(&hScan);
      }
      while (pTable != NULL;
   }
}

Find Active Table

CTDatabase::FindActive() locates a specific active table and returns the table object pointer. If the table is not active, CTDatabase::FindActive() returns NULL.

// Check if table is active
CTBOOL IsTableActive(CTDatabase& ADatabase, CTString& tblName)
{
   return (ADatabase.FindActive(tblName) != NULL) ? YES : NO;
}

The function above is shown for example purposes only as the FairCom DB API method CTTable::IsActive() provides a more efficient way to check if a table is active.

Table UID (Unique IDentifier)

When a table is created or added to a database, an automatic and unique identifier (UID) is associated with the table. A table UID is unique within the database that the table is associated with.

A table UID is an unsigned long value that can be used as an alternative method to operate on tables once the table is created or added to a database.

Find Table by UID

The overloaded method CTDatabase::FindTable() locates a table in the database given the table UID and retrieves the table name and path. The following example shows how to implement a table open function using the table UID instead of the table name.

// open table using UID
CTTable* OpenByUID(CTDatabase& ADatabase, ULONG uid, CTOPEN_MODE OpenMode)
{
   CTString tblName;
   CTString tblPath;
   CTTable* Retval;
 
   // locate the table in the database by uid
   if (ADatabase.FindTable(uid, tblName, tblPath))
   {
      Retval = new CTTable(ADatabase);
   
      if (!Retval)
         throw CTException(CTDBRET_NOMEMORY);
   
      try
      {
         Retval->Open(tblName, OpenMode);
      }
      catch (CTException& err)
      {
         delete Retval;
         throw;
      }
   }
   else
   {
      // table not found
      throw CTException(INOT_ERR);
   }
   return Retval;
}

Find active Table by UID

The overloaded method CTDatabase::FindActive() locates an active table given its UID number and returns the active table object pointer. The following example shows how to check if a table is active using its UID number.

// check if atable is active, by UID
CTBOOL IsTableActive(CTDatabase& ADatabase, ULONG uid)
{
return (ADatabase. FindActive(uid) != NULL) ? YES : NO;
}

 

Database Dictionary

A database must have a database dictionary; this file has the database name with extension .fdd. It is created with CTDatabase::CreateDatabase(), and must exist for the user to connect to the database. Each database dictionary maintains information about the tables associated with the database. When a database is connected to the session, it is considered "active".

Database Dictionary Layout

Field Type Length Description
TYPE CT_INT4 4 Record type: 1-database 2-table 3-index
STATUS CT_INT4 4 Record status: 0-status ok 1-reserved
LOGICAL_NAME CT_FSTRING 128 Logical (database) name of database or table or index
PHYSICAL_NAME CT_FSTRING 128 Physical name of database or table or index
LINK CT_FSTRING 128 Name of table if record type is 3-index
LINKNBR CT_INT4 4 Table UID if record type is 3-index
PATH CT_FSTRING 256 Path of database dictionary, data or index
SUPEXT CT_FSTRING 16 Super file extension (if super file is used)
DATEXT CT_FSTRING 16 Data file extension (usually .DAT)
IDXEXT CT_FSTRING 16 Index file extension (usually .IDX)
VERSION CT_INT4 4 Record version: 0x00010000 (version 1.0)
COUNTER CT_INT4 4 Deprecated.
UID CT_INT4 4 UID for database or table or index
OWNER CT_FSTRING 128 Name of owner - used by the FairCom DB SQL server
MIRROR_NAME CT_FSTRING 128 Name of mirrored file.
MIRROR_PATH CT_FSTRING 128 Path of mirrored file.
RESERVED CT_ARRAY 3000 Reserved for future use

This information is included for general information on the database dictionary structure. FairCom DB API has appropriate functions to retrieve any needed information from the database dictionary, such as the table UID or path.

A database dictionary file has several different record types:

  • Table records (the field Type set to 2) holds information about a data file (table).
  • Index records (the field Type set to 3) holds information about an index file.
  • A special type four record which maintained the COUNTER field has been been deprecated as of FairCom DB V9.0.