Working with Sessions

Overview

FairCom DB API uses "sessions" to manage connections between client applications and c-tree Servers. Unlike many other types of sessions that are used by computers and computer networking systems, a FairCom DB API session has a dual nature: part of the session is persistent, and is shared between multiple client applications, and part of the session is not. It is important to understand how this works.

A FairCom DB API session consists of two separate entities, each of which resides in a different location: (1) a persistent, shared "session dictionary", and (2) a per-client "session handle".

Session Dictionary

The session dictionary is a persistent file that resides on the server. This file contains configuration information for the session, such as which databases are available to the users of that session, where the files for those databases are located, etc. When a client application logs into a session, it is connecting to, and using, the session dictionary file. It might help to think of the session dictionary file as maintaining the "database environment". Note that it is possible to create multiple session dictionary files on the server (using ctdbSetSessionPath() and ctdbCreateSession()), and configure each one differently, but this not commonly done. Most systems use only a single session dictionary file.

The session dictionary file is shared among all client applications that log into that session. A client application that logs into that session has access to the databases and resources that have been added to that session dictionary. Furthermore, any client application that is logged into a session can modify the contents of that session's session dictionary (by adding and removing databases from it, for example). When modifying the session dictionary, it is very important to remember that the dictionary is shared. Any changes to the session dictionary will be instantly seen by any other client applications that is currently logged into that session, or that log into it in the future. (Removing a database from a session dictionary will make that database unavailable to all other client applications that are currently logged into that session.) For this reason, modifying a session dictionary is generally considered to be a "server configuration" type of task, which is done rarely, and with deliberation and care. Generally, you add the database(s) you need to the session dictionary and then forget about the session dictionary. (Programmers who are using the single-client / single-user models of FairCom DB API do not have to worry about affecting multiple simultaneous client applications, but still need to remember that the session dictionary is persistent - it will remember the state it was in from the last time you logged onto that session.)

Session Handle

The other part of a session is a C pointer variable that is inside each client application program, and is called a "session handle". The session handle is private to each client application, so it is NOT shared between clients. Each client application allocates, initializes, and maintains its own session handle, and then deallocates it before exiting. The session handle represents a connection between a client and a FairCom Server database engine, and indicates the session type, the session dictionary, the server name and location of the session dictionary.

When working with FairCom DB API sessions, it is important to keep in mind which part of the session you are operating on - the shared, persistent session dictionary, or the private, volatile session handle, so you do not accidentally interfere with other client applications that are logged into the same session.

The FairCom DB API interface requires a session handle (which represents a connection to the database server) to perform any data structure initialization or manipulation. The following steps must be executed to set up a session before any database or table operations are attempted:

  • Allocate a session handle by calling ctdbAllocSession().
  • Logon to a c-tree session (connect to a session dictionary) by calling ctdbLogon().
  • Perform database and table operations.
  • Logout from a c-tree session by calling ctdbLogout().
  • Release the allocated session handle by calling ctdbFreeSession().

Allocating a Session Handle

A valid session handle is required to perform any session operation. The session handle must be allocated using ctdbAllocSession(). When the session handle is no longer needed it may be freed using ctdbFreeSession().

CTHANDLE hSession;
hSession = ctdbAllocSession(CTSESSION_CTDB);
if (!hSession)
   FatalError("Session handle allocation failed\n");
/* ... some other statements ... */
ctdbFreeSession(hSession);

When allocating a session handle, specify the session handle type. There are three different session handle types:

CTSESSION_CTREE

This session mode is intended for existing ISAM applications that want access to some of the FairCom DB API functionality, which is higher-level and easier-to-code than ISAM. Consider this mode as a stepping stone that allows ISAM applications to be modified to start using FairCom DB API functions a little at a time.

This mode allocates a new session handle for logon to the server only—it does NOT connect to the persistent session dictionary on the server. That means that many of the features available in the c-tree API (like database dictionaries and the database-specific functions) will not be available.

This session mode provides direct, low-level access to the table and index files on disk. This mode is higher-level than ISAM, but lower-level than FairCom DB API and SQL modes, which means that many of the higher-level database functions provided by the FairCom DB API API are not available in this mode. When using this session mode, allocate table handles using the session handle.

CTSESSION_CTDB

Allocate a new session making full use of a FairCom DB API session dictionary and the database dictionaries. Tables and fields/columns can be accessed using their logical names rather than paths on disk and column numbers.

The full database functions of the FairCom DB API API are available, providing high-level function calls which greatly simplifies the client application code. Table and index creation and modification is significantly easier, because this mode hides the complexity of the low-level ISAM layer, so the programmer can focus on the tables and indexes being created.

This session also maintains the SQL "NULL" field for you. With this session mode, a Session dictionary file must exist to perform a session logon and you must connect to a database before attempting to perform operations on tables.

CTSESSION_SQL

Allocate a new session using FairCom DB API session and database dictionaries. Once logged on a server, if the server is SQL then database creation creates a SQL database. Once connected to a database, if the database is a SQL database and the table is associated with the database, then table and index creation, deletion, modifications are reflected in SQL system tables.

Note that database creation and table creation are slightly slower in this mode, but all other operations (table searching, record creation and deletion, etc) are just as fast as with the other session modes.

CTSESSION_SQL Limitations

CTSESSION_SQL mode has the following limitation:

  • Problems with table structures will prevent update of FairCom DB SQL system tables.

Creating a New Session Dictionary

When operating with sessions of type CTSESSION_CTDB or CTSESSION_SQL, a session dictionary file named ctdbdict.fsd is required before a session logon is performed. The session dictionary file ctdbdict.fsd is located by default either in the server directory (client/server application) or in the execution directory (stand-alone application).

There could be situations where the FairCom DB API session dictionary file does not exist because it was deleted or this is the very first time the system is being executed. In this case it is necessary to create a session dictionary file before attempting to logon to a session. It is important to note that only one session dictionary file is necessary for the normal operation of FairCom DB API. Once created, the session dictionary file can be used for all database and table operations.

The following code fragment shows an example on how to create a new session dictionary file:

CTHANDLE hSession;  
hSession = ctdbAllocSession(CTSESSION_CTDB);
if (!hSession)
   FatalError("Session handle allocation failed\n");
if (ctdbCreateSession(hSession, "FAIRCOMS", "ADMIN", "ADMIN") != CTDBRET_OK)
   FatalError("Error creating session dictionary file\n");

Note: The above code, as most of the pseudocode presented in this manual, does not make use of error checking. While not an appropriate programming style, it is used in this manual for clarity of the functional code presented.

These lines represent all three steps required to create the session dictionary. First, a session handle is declared. FairCom DB API uses Opaque handles, and the best approach is to use the declaration as done above with CTHANDLE, which is a pointer to void. All FairCom DB API handles should be defined this way. The next call, ctdbAllocSession(), makes the physical handle allocation. All FairCom DB API C functions are described in detail in FairCom DB API C API Function Reference.

After allocating a session handle, it is possible to log on to a session if the session dictionary already exists in the working directory. If not, a new session dictionary must be created using ctdbCreateSession().

In the above example, the session dictionary is created using ctdbCreateSession(), which requires four parameters: session handle, server name, user name, and user password. For the three last parameters, in this first example, the default values are being used.

The full network address may be required in the Server name: FAIRCOMS@10.0.0.1 or FAIRCOMS@my_machine.com. For non-server applications, the parameter is ignored and may be set to NULL.

A valid user name is required to access the c-tree Server. When the server is first installed, only the default user is permitted server access. This user name, ADMIN, is intended for the database administrator. ADMIN is also the default user name for FairCom DB API sessions. For non-server applications, the user name may be NULL. For server applications, see the c-tree Server Administrator’s Guide on how to create users and groups.

A valid user password is also required to access the c-tree Server. When the server is first installed, the default user ADMIN is associated with the default password, also ADMIN. For non-server applications, the user password may be NULL.

ctdbCreateSession() will return error DPON_ERR (19, data file already exists) if one tries to create a new session dictionary in the same directory where a session dictionary already exists.


Session Logon and Logout

To perform any database operations, it is necessary to log on to a c-tree session. A session is terminated with a session logout.

To log on to a session, a session handle must be allocated with ctdbAllocSession() and then ctdbLogon() is called to perform the session logon.

CTHANDLE hSession = ctdbAllocSession(CTSESSION_CTDB);
if (!hSession)
   FatalError("Session handle allocation failed\n");
if (ctdbLogon(hSession, "FAIRCOMS", "ADMIN", "ADMIN") != CTDBRET_OK)
   FatalError("Session logon failed\n");

The parameters for the ctdbLogon() function are the same as for the ctdbCreateSession(). If the session dictionary doesn't exist and the session type is CTSESSION_CTDB or CTSESSION_SQL, ctdbLogon() function will fail returning error FNOP_ERR (12), indicating that FairCom DB API could not locate the session dictionary file.

Tip: A useful sequence is to try to log on to the session, and if it fails with error FNOP_ERR (12), create the session dictionary and then log on again.

CTSESSION hSession;
hSession = ctdbAllocSession(CTSESSION_CTDB);
if (!hSession)
   FatalError("Session handle allocation failed\n");
if (ctdbLogon(hSession, "FAIRCOMS", "ADMIN", "ADMIN") == FNOP_ERR)
{
   if (ctdbCreateSession(hSession, "FAIRCOMS", "ADMIN", "ADMIN")!= CTDBRET_OK)
      FatalError("Error creating session dictionary file\n");
   if (ctdbLogon(hSession, "FAIRCOMS", "ADMIN", "ADMIN") != CTDBRET_OK)
      FatalError("Session logon failed\n");
}

When operations with the session are no longer needed, it is necessary to logout from the session by calling ctdbLogout().

CTHANDLE hSession;
hSession = ctdbAllocSession(CTSESSION_CTDB);
if (!hSession)
   FatalError("Session handle allocation failed\n");
if (ctdbLogon(hSession, "FAIRCOMS", "ADMIN", "ADMIN") != CTDBRET_OK)
   FatalError("Session logon failed\n");
/* perform some other operations on databases and tables */
if (ctdbLogout(hSession) != CTDBRET_OK)
   FatalError("Session logout failed\n");
ctdbFreeSession(hSession);

Session Properties

The default session properties are suitable for most FairCom DB API applications. Advanced developers may need to tune FairCom DB API to meet application requirements. Use ctdbSetSessionParams() to set the following properties:

Property Description Default
BUFS Index file buffers 10
FILS File structure blocks 32
SECT Node sectors 32
DBUFS Data file buffers 10
USERPROF User profile mask 513

The default USERPROF value of 513 tells single-user, transaction-control applications to remove the auxiliary log files S*.FCS and L*.FCS upon successful termination of the application, and also removes the automatic key transformation. The table below presents the bit values for the USERPROF parameter. They can be combined by OR’ing them together.

The table below present all possible values for the USERPROF parameter. See InitISAMXtd for detailed descriptions.

User Profile Values

Keyword Value Explanation
USERPRF_NTKEY 1 Do not perform auto tfrmkey
USERPRF_SAVENV 2 Savenv mode for transactions
USERPRF_NDATA 32 Do not perform auto data - UNIFRMAT conversion
USERPRF_LOCLIB 64 Use a local library: not server
USERPRF_PTHTMP 128 Add tmpname to input path, otherwise use system tmpname
USERPRF_CLRCHK 512 Clear transaction logs

Example

/* setting different user profile before logging on to session */
ctdbSetSessionParam(hSession, USERPROF, (USERPRF_NTKEY | USERPROF_CLRCHK));
if (ctdbLogon(hSession, "FAIRCOMS", "ADMIN", "ADMIN) != CTDBRET_OK)
   FatalError("Session logon failed\n");

Server, user name and password properties

Once a session is active, the user may retrieve the server name for the session with ctdbGetServerName(). Retrieve the user name by calling the ctdbGetUserLogonName() function.

Please refer to the example in Active property.

Active property

A session is active if the user has logged on to a valid session dictionary using ctdbLogon(). To render a session inactive, log off using ctdbLogout(). To verify the status of the session, use ctdbIsActiveSession().

Example


/* if session is active, retrieve the server name and user logon name */
if (ctdbIsActiveSession(hSession))
{
   printf("Server name: %s\n", ctdbGetServerName(hSession));
   printf("User name  : %s\n", ctdbGetUserLogonName(hSession));
}

Path property

The default path for client/server applications is the server directory, while the default path for non-server applications is the execution directory. If, for any reason, there is the need to modify the location of the session dictionary on the server, the function ctdbSetSessionPath() may be used, before creating and/or logging on to the session. ctdbGetSessionPath() may be used to retrieve the path for an active session. Note that ctdbGetSessionPath() will return an empty result until the default path has been set with a call to ctdbSetSessionPath().

Using this property, it is even possible to have multiple session dictionaries, in separate directories. This is not required, since the concepts of restricting access to different users to diverse tables or databases may be implemented inside a unique session dictionary.

The example below shows how to use the ctdbSetSessionPath() function to create a session dictionary file in a user specified directory, instead of the default directory

Example


CTHANDLE hSession;  

hSession = ctdbAllocSession(CTSESSION_CTDB);
if (!hSession)
   FatalError("Session handle allocation failed\n");

ctdbSetSessionPath(hSession, "\new\session\dictionary");
if (ctdbCreateSession(hSession, "FAIRCOMS", "ADMIN", "ADMIN") != CTDBRET_OK)
   FatalError("Error creating session dictionary file\n");

Managing Databases

Once the user performs a successful Session Logon, the session handle can be used to operate on databases.

Every time a new database is created, or an existing database is added to a session, the database properties such as database name and path are placed in an entry of the session dictionary file.

Every time a user activates a database by connecting using ctdbConnect(), the handle of that database is placed in a list of active (connected) databases within the session handle. When a database is deactivated or disconnected by calling ctdbDisconnect(), the database handle is removed from the list of active databases in that session handle. A user may query the active database list in a given session handle by locating the first active database, the next active database, or finding a specific active database. A database is "active" for a given client application if that client has a database handle that is currently connected to that database. Note that this does not make the database "active" for any other client applications that might be connected to that session dictionary. In other words, if a database is "active" for one client that is logged into the session, it is not necessarily "active" for any other clients that are logged into the same session.

Creating a New Database

Use ctdbCreateDatabase() to create a new database dictionary. ctdbCreateDatabase() takes a session or a database handle, the database name, and the path where the database dictionary file is to be located. If the database path is NULL or empty ("") the database is created in the server directory for client/server applications, or in the execution directory for standalone applications.

/* create a new database MyDatabase */
if (ctdbCreateDatabase(hSession, "MyDatabase", "") != CTDBRET_OK)
{
   printf("Create database failed\n");
}

ctdbCreateDatabase() creates a new database dictionary file with the database name and extension .FDD (FairCom Database Dictionary). Using the example above, the database dictionary file created is MyDatabase.fdd. Note that ctdbCreateDatabase() adds the new database to the specified session dictionary.

Adding an Existing Database

Use ctdbAddDatabase() to add an existing database to the current session dictionary. ctdbAddDatabase() takes a session or a database handle, the database name and the path where the database is located.

/* add MyDatabase to the current session */
if (ctdbAddDatabase(hSession, "MyDatabase", "") != CTDBRET_OK)
{
   printf("Add database failed\n");
}

Dropping a Database

When you drop a database from a session, the database information is removed from the session dictionary, but the database dictionary file is left untouched. The drop database operation can be reversed with an add database operation. Drop a database from a session dictionary by calling ctdbDropDatabase().

/* drop MyDatabase from current session dictionary */
if (ctdbDropDatabase(hSession, "MyDatabase") != CTDBRET_OK)
{
   printf("Drop database failed\n");
}

Deleting a Database

When you delete a database from a session, the database information is removed from the session dictionary and the database dictionary file is deleted. The delete database operation cannot be reversed and the database dictionary data will be lost. Delete a database from a session by calling ctdbDeleteDatabase().

/* delete MyDatabase from current session dictionary and from disk */
if (ctdbDeleteDatabase(hSession, "MyDatabase") != CTDBRET_OK)
{
   printf("Delete database failed\n");
}

First Database

ctdbFirstDatabase() retrieves the name and path of the first database in a session dictionary. If the session dictionary has no databases, ctdbFirstDatabase() returns an INOT_ERR (101) code.

Next Database

ctdbNextDatabase() retrieves the name and path of the next database in a session dictionary. ctdbNextDatabase() returns INOT_ERR (101) after it has listed all of the databases in that session dictionary.

/* display all databases in a session */
CTDBRET DisplayDatabases(CTHANDLE hSession)
{
    CTDBRET Retval;
    TEXT dbName[MAX_NAME];
    TEXT dbPath[MAX_NAME];

    if ((Retval = ctdbFirstDatabase(hSession, dbName, sizeof(dbName), dbPath, sizeof(dbPath)) == CTDBRET_OK)
        do
        {
           printf("Database: %s Path:%s\n", dbName, dbPath);
           Retval = ctdbNextDatabase(hSession,
                dbName, sizeof(dbName), dbPath, sizeof(dbPath));
        }
        while (Retval = CTDBRET_OK);

    if (Retval == INOT_ERR)
         Retval = CTDBRET_OK;

    return Retval;
}

Find Database

ctdbFindDatabase() retrieves the path of a specific database in a session dictionary given the database name. If the database is not in the session dictionary, ctdbFindDatabase() returns INOT_ERR (101).

/* return YES if database exist or NO if database does not exit */
CTBOOL DatabaseExist(CTHANDLE hSession, pTEXT dbName)
{
    TEXT dbPath[MAX_NAME];

    return (ctdbFindDatabase(hSession, dbName, dbPath,
            sizeof(dbPath)) == CTDBRET_OK) ? YES : NO;
}

The three functions just discussed are used to obtain the name and/or path of any databases that are in the session dictionary. The following three functions are used to obtain the database handles of the databases in the session dictionary. These functions have "Active" in their names because they only return the handles of "active" databases, ie. databases that are currently connected to the session via a database handle. These functions can not return database handles of non-active databases, because non-active databases do not have database handles.

First Active Database

ctdbGetFirstActiveDatabase() retrieves the database handle of the first active/connected database in the session. ctdbGetFirstActiveDatabase() returns NULL if the session contains no active databases.

Next Active Database

ctdbGetNextActiveDatabase() retrieves the database handle of the next active/connected database in the session. When the handle of the last active/connected database has already been retrieved, ctdbGetNextActiveDatabase() returns NULL.

/* Display all active databases */
void DisplayActiveDatabases(CTHANDLE hSesssion)
{
   VRLEN hScan;
   CTHANDLE hDatabase;

   if ((hDatabase = ctdbGetFirstActiveDatabase(hSession, &hScan)) != NULL)
   {
      do
      {
         printf("Database: %s Path: %s\n", ctdbGetDatabaseName(hDatabase),
            ctdbGetDatabasePath(hDatabase));
         hDatabase = ctdbGetNextActiveDatabase(hSession, &hScan);
      }
      while (hDatabase != NULL;
   }
}

Find Active Database

ctdbFindActiveDatabase() retrieves the handle of a specific active/connected database in the session. If the named database is not in the session dictionary, or is not active/connected, ctdbFindActiveDatabase() returns NULL.

/* Check if database is active */
CTBOOL IsDatabaseActive(CTHANDLE hSession, pTEXT dbName)
{
   return (ctdbFindActiveDatabase(hSession, dbName) != NULL) ? YES : NO;
}

The function above is shown for example only. The FairCom DB API API function ctdbIsActiveDatabase() provides a more efficient way to check if a database is active.

Database UID (Unique IDentifier)

When a database is created or added to a session dictionary, an automatic and unique identifier is associated with the database. (Note that creating a database implicitly adds it to the specified session dictionary.) A database UID is unique within the session that the database is associated with. In other words, as long as a database is left in the session dictionary, the database’s UID will not change. Removing the database from the session dictionary and then re-adding it to the session dictionary will very likely change the UID.

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

Find Database by UID

ctdbFindDatabaseByUID() retrieves the name and path of any database in a session dictionary given the database UID. ctdbFindDatabaseByUID() requires a session handle or the handle of any database that is currently connected to the session you wish to search. The following example shows how to implement a database connect procedure using the database UID instead of the database name.

/* Database Connect using UID */
CTDBRET ConnectByUID(CTHANDLE hDatabase, ULONG uid)
{
   TEXT dbName[MAX_NAME];
   TEXT dbPath[MAX_PATH];
   CTDBRET Retval;

   Retval = ctdbFindDatabaseByUID(hDatabase, uid, dbName, sizeof(dbName), Path,
            sizeof(dbPath));
   if (Retval == CTDBRET_OK)
   {
      Retval = ctdbConnect(hDatabase, dbName);
   }
   return Retval;
}

Find Active Database by UID

ctdbFindActiveDatabaseByUID() retrieves the database handle of an active/connected database in the session dictionary given its UID. The following example shows how to check if a database is active using its UID.

/* check if database is active, by UID */
CTBOOL IsActiveDatabaseByUID(CTHANDLE hSession, ULONG uid)
{
   return (ctdbFindActiveDatabaseByUID(hSession, uid) != NULL) ? YES : NO;
}

Session-Wide Functions

There is a group of functions that are generic enough to operate with any one of the FairCom DB API API handles. Although these functions require a handle to operate on, they accept any one of the FairCom DB API session, database, table, record, field, index and segment handles.

Error Handling

Most FairCom DB API API functions return an error status to indicate if a particular function operation succeeded or not. Most FairCom DB API API functions will also keep the last error status, if the function operation failed. The last error status can be manipulated with the following functions:

  • ctdbGetError() retrieves the last error status. If a function succeeds, the success status is not kept by the FairCom DB API API.
  • ctdbSetError() sets the last error status, overwriting any previous error status kept by the FairCom DB API API.
  • ctdbClearError() clears the last error status.
/* clear error if error is INOT_ERR */
if (ctdbGetError(AnyHandle) == INOT_ERR)
{
   ctdbClearError(AnyHandle);
}

Transaction Processing

The FairCom DB API API implementation of its transaction processing functions closely follows the existing FairCom DB ISAM API. The basic difference between the two transaction processing APIs is the separation of locking from the "begin transaction" functions. While the FairCom DB ISAM "begin transaction" function also turns on locking, the FairCom DB API "begin transaction" function does not.

Note that the FairCom DB API functions to END a transaction (ctdbCommit() and ctdbAbort()) do include unlocking behavior. They turn off session-wide locking AND release all locks (both locks automatically acquired via the session-wide locking mechanism and locks manually acquired by calling ctdbLockRecord()).

The code fragment below shows an example using the FairCom DB ISAM calls to process a transaction with locking:

/* start transaction enabling write locks */
TRANBEG(TRNLOG | ENABLE | LK_BLOCK);

... perform some data operations ...

/* commit the transaction and release locks */
TRANEND(FREE);

The FairCom DB ISAM code fragment above starts a transaction by invoking TRANBEG(). The mode ENABLE indicates that every FairCom DB read record operation will lock the record for writing. The mode LK_BLOCK indicates that the thread will block until the lock is acquired.

When using the FairCom DB API API on the other hand, the call that starts transaction processing will not start the session-wide record-locking mechanism. The code fragment below shows the equivalent example using the FairCom DB API API:

/* start a transaction */
ctdbBegin(AnyHandle);

/* enable blocking write locks */
ctdbLock(AnyHandle, CTLOCK_WRITE_BLOCK);

... perform some data operations ...

/* commit transaction, release locks, turn off session-wide record locking */
ctdbCommit(AnyHandle);

ctdbBegin() starts a new transaction.

ctdbLock() turns on session-wide record WRITE locking, in "blocking" mode. (See Session-Wide Record Locking.) After that, any attempts to read, change, or delete a record will automatically lock that record with a write lock. If the write lock cannot be obtained for that record (because another client application / thread already has a conflicting lock on that record, for example), then ctdbLock() will block until the lock can be obtained (as specified by the word "_BLOCK" in "CTLOCK_WRITE_BLOCK").

ctdbCommit() terminates the transaction by committing any changes. Note that ctdbCommit() also turns off session-wide record locking, and releases all of the record locks. Here are some other functions that you might use in this context:

ctdbAbort() terminates a transaction and aborts any changes done during the transaction (and turns off session-wide record locking, and releases all of the record locks).

ctdbSetSavePoint() and ctdbSetSingleSavePoint() set a savepoint in the current transaction. Once a save point is set within the current transaction, ctdbRestoreSavePoint() will reverse only the changes done between the set save point call and the restore save point call without terminating the transaction.

It is important to realize that FairCom DB API transactions are session-wide, and since FairCom DB API does not support nested transactions, you can only have one transaction "open" at a time. If you call ctdbBegin() twice in a row, the second call will return an error. You can use save points to mimic nested transactions, though.

Refer to Data Integrity for detailed description of FairCom DB API API for transaction processing, save points, and locking.

Session-Wide Record Locking

Locking is a useful mechanism that can be used to promote data integrity when you have a situation where multiple clients or multiple client threads are accessing the same tables simultaneously.

Session-wide record locking is based on the principle that ctdbLock() sets the current session-wide lock mode (but does not actually lock any records when it is called). When locking is activated this way, every record read, write, or delete of all active tables of all active databases associated with the session are automatically locked with the current session-wide lock mode (as set by the ctdbLock() call).

ctdbUnlock() releases all locks automatically acquired since session-wide record locking was turned on and clears the current session-wide lock mode, with certain exceptions – see the ctdbUnlock() function). Notice that ctdbCommit() and ctdbAbort() release all locks and clear the current session-wide lock mode.

ctdbIsLockActive() indicates if a session-wide lock mode is set. (In other words, if record reads, writes, and deletes will automatically be locked or not).

ctdbGetLockMode() retrieves the current session-wide lock mode. If the session-wide lock system is turned off, ctdbGetLockMode() returns CTLOCK_FREE.

Refer to Data Integrity for detailed description of the FairCom DB API API for transaction processing and locking.

Default Date, Time and Float formats

The FairCom DB API record manager performs automatic data type conversions when the user reads from, or writes to, a field using a data type different from the field data type. For most data types, the conversion is straight forward except when converting dates and times from and to strings, since there are many different conventions for displaying dates and times.

By default the FairCom DB API API converts date to string, and from string to date, using the standard USA convention of MM/DD/CCYY, where MM represents a two-digit month value from 01 to 12, DD represents a two-digit day of the month value from 01 to 31 (depending on the number of days in the month), CC represents a two-digit century, and YY represents a two-digit year. A date separator may be one of the following characters: '/', '-', or '.'.

The FairCom DB API API also converts time to string, and string to time, using the standard USA convention of HH:MM AM where HH represents the hour value from 1 to 12, MM represents the minutes value from 1 to 59, and AM represents AM or PM values.

ctdbSetDefDateType() sets a new default date format. ctdbGetDefDateType() retrieves the current default date format. The following date formats are supported:

CTDATE_MDCY Date format is MM/DD/CCYY where MM represents a two-digit month, DD represents a two-digit day of the month, CC represents a two-digit century, and YY represents a two-digit year. The date separator may be one of the following characters: '/', '-', or '.'. This is the default date format. Example: 12/01/2002.
CTDATE_MDY Date format is MM/DD/YY where MM represents a two-digit month, DD represents a two-digit day of the month, and YY represents a two-digit year. The date separator may be one of the following characters: '/', '-', or '.'. Example: 12/01/02
CTDATE_DMCY Date format is DD/MM/CCYY where DD represents a two-digit day, MM represents a two-digit month , CC represents a two-digit century, and YY represents a two-digit year. The date separator may be one of the following characters: '/', '-', or '.'. Example: 01/12/2002.
CTDATE_DMY Date format is DD/MM/YY where DD represents a two-digit day, MM represents a two-digit month, and YY represents a two-digit year. The date separator may be one of the following characters: '/', '-', or '.'. Example: 01/12/02.
CTDATE_CYMD Date format is CCYYMMDD where CC is a two-digit century, YY is a two-digit date, MM is a two-digit month, and DD is a two-digit day of the month. This date format has no separators. Example: 20021201.
CTDATE_YMD The date format is YYMMDD where YY represents a two-digit year, MM represents a two-digit month, and DD represents a two-digit day of the month. This date format has no separators. Example: 021201

ctdbSetDefTimeType() sets a new default time format. ctdbGetDefTimeType() retrieves the current default time format. The following time formats are supported:

CTTIME_HMSP Time format is HH:MM:SS AP where HH represents the hour with values between 1 and 12, MM represents a two-digit minute value between 00 and 59, SS represents a two-digit second value between 00 and 59 and AP is either AM or PM. The time separator may be ':' or '.'. Example: 1:35:45 AM.
CTTIME_HMP Time format is HH:MM AP where HH represents the hour with values between 1 and 12, MM represents a two-digit minute value between 00 and 59 and AP is either AM or PM. The time separator may be either ':' or '.'. Example: 1:35 AM.
CTTIME_HMS Time format is HH:MM:SS where HH represents an hour value between 0 and 23, MM represents a two-digit minute value between 00 and 59, and SS represents a two-digit second value between 00 and 59. The time separator may be either ':' or '.'. Example: 1:35:45
CTTIME_HM Time format is HH:MM where HH represents an hour value between 0 and 23, MM represents a two-digit minute value between 00 and 59. The time separator may be either ':' or '.'. Example: 1:35.
CTTIME_MIL Time format is HHMM (military format). HH represents a two-digit hour value between 00 and 23 and MM represents a two-digit minute value between 00 and 59. This time format has no separator. Example: 0135.

When converting floating point type fields, such as CT_SFLOAT, CT_DFLOAT and CT_EFLOAT to and from strings, FairCom DB API uses the same float conversion format used by the C standard library functions printf() and scanf(). By default the float conversion format is set to "%f". Use ctdbSetDefFloatFormat() to set a new default float conversion format. Use ctdbGetDefFloatFormat() to retrieve the current default float conversion format.

User Defined Tags

Every handle allocated by the FairCom DB API API has a space called user tag value reserved for holding an arbitrary user value. The user tag has no predefined meaning and is provided for the convenience of developers. It can be used for storing an additional void pointer or it can be typecast to any 32-bit value (or 64-bit value on 64-bit platforms).

Use ctdbGetUserTag() to retrieve the current user tag value associated with a handle. Use ctdbSetUserTag() to set the current user tag value associated with a handle. Both ctdbGetUserTag() and ctdbSetUserTag() accept any handle allocated by the ctdbAllocXXX() functions of the FairCom DB API API.

When a FairCom DB API handle is released by calling one of the ctdbFree ...() functions, the user tag value is not automatically released. The user is responsible for releasing any dynamic memory controlled by pointers stored in the handle user tag space.


Working with Sessions without Dictionary Support

There are situations where it is necessary to operate with a table that does not belong to a database, or where a session or database dictionary file is not required. For these situations the user may want to allocate a session handle of type CTSESSION_CTREE.

CTSESSION hSession;
hSession = ctdbAllocSession(CTSESSION_CTREE);
if (!hSession)
   FatalError("Session handle allocation failed\n");
if (ctdbLogon(hSession, "FAIRCOMS", "ADMIN", "ADMIN") != CTDBRET_OK)
   FatalError("Session logon failed\n");

The ctdbLogon() call above performs a c-tree logon but it will not attempt to open a session dictionary file. The same result is obtained by allocating a CTSESSION_CTDB or CTSESSION_SQL session but calling ctdbSetLogonOnly() before ctdbLogon().

CTSESSION hSession;
hSession = ctdbAllocSession(CTSESSION_CTDB);
if (!hSession)
   FatalError("Session handle allocation failed\n");
ctdbSetLogonOnly(hSession, YES);
if (ctdbLogon(hSession, "FAIRCOMS", "ADMIN", "ADMIN") != CTDBRET_OK)
   FatalError("Session logon failed\n");

Attach and Detach Existing Sessions

There are situations where an existing connection to c-tree already exists, via a call to a low level or ISAM c-tree initialization function, but FairCom DB API functionality is required without terminating the existing connection and starting a new FairCom DB API session. The following functions are available to permit a session handle to be attached and detached from an existing c-tree connection.

ctdbAttachSession() attaches an inactive session handle to an existing c-tree Plus or FairCom DB API session. Attached sessions have no information on server, user name or user password, and these values are set to NULL. If a ctdbLogout() is performed on an attached session handle, no session logout is performed and a ctdbDetachSession() call is executed instead.

There are three valid mode values:

mode Parameter Description
CTATTACH_SESSION Attach to a FairCom DB API session whose session handle is pointed by parameter source.
CTATTACH_CTREEID Attach to a FairCom DB session whose instance id string is pointed by parameter source.
CTATTACH_CURRENT Attach to the current c-tree instance. Contents of parameter source is ignored, as the c-tree instance id is obtained by calling WCHCTREE() function.

ctdbDetachSession() detaches a FairCom DB API session handle. The c-tree ISAM or low-level un-initialization is not called, but the session handle control structures are released and re-initialized. Handle is a session handle allocated by ctdbAllocSesison(). ctdbDetachSession() returns CTDBRET_OK on success.

Example

/* logon to c-tree using ISAM function */
INTISAMX(10, 32, 32, 10, (USERPRF_NTKEY | USERPRF_CLRCHK));

/* attach session to server handle */
if (ctdbAttachSession(hSession, NO) != CTDBRET_OK)
    printf("ctdbAttachSession failed\n");

/*
    ... do something useful ...
*/

/* detach from session */
if (ctdbDetachSession(hSession) != CTDBRET_OK)
    printf("ctdbDetachSession failed\n");

/* perform an ISAM logout */
CLISAM();

Session Dictionary

The session dictionary is a collection of databases, and each record of the session dictionary file contains the information of a particular database. In general, just one session dictionary file exists, ctdbdict.fsd, located by default in the execution directory (client/server development) or in the execution directory (stand-alone application). The table below represents the general layout of a session dictionary file:

Session 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
NAME CT_FSTRING 128 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 c-treeSQL server
MIRROR_NAME CT_FSTRING 128 Name of mirrored file.
MIRROR_PATH CT_FSTRING 128 Path of mirrored file.
RESERVED CT_ARRAY 3128 Reserved for future use

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

A session dictionary file has several different record types:

  • Database records (the field Type set to 1) holds information about databases.
  • A special type four record which maintained the COUNTER field has been been deprecated as of FairCom DB V9.0.