Working with Resources

It can be advantageous at times to attach auxiliary information to a particular table that does not conform to the record structure of that table. For example, features such as versioning or special flags relating to the status of the table. Generally, this information is not repeated in every record of the table. You could create a special record, with a special key value, that you do not process as you do your regular records. Ultimately, however, this forces exceptional handling routines for this special case and can impose a heavy maintenance cost on the life cycle of the application.

FairCom DB provides a unique feature created for exactly this purpose: FairCom DB Resources. Resources are special variable-length records stored within your data file, whether you use fixed or variable-length records. A set of FairCom DB API functions provide access to create, update, and delete these resource records. These records do not require a key in an index, therefore your program does not access them via routine data handling functions.

Resources provide critical support for many advanced FairCom DB features. FairCom-defined resources allow seamless functionality of many of the Incremental ISAM features, conditional index support, FairCom DB API, FairCom DB SQL, c-tree ODBC Drivers, and the r-tree Report Engine. These resources continue to be important as new technology is added. Resources are added either automatically by some FairCom DB features or manually by the developer. The use of resources requires the RESOURCES define in the FairCom DB library, which is the default.

This section focuses on user defined resources added by you, the developer, and provides important background information on the use of resources.

Types of Resources

There are three general types of resources that can be attached to a file.

User-defined resources

Information that you wish to store in the table, such as a version number, or an infrequently accessed counter. Use resources to store information associated with a table that varies from the type of information stored repetitively in the data records.

FairCom-defined resources

There is a variety of information that, under certain circumstances, FairCom wishes to store in the table. This can be information relating to IFIL structures, alternate collating sequences, special characters for key padding, and so forth. Usually you do not access this information directly. It is available to a variety of FairCom DB API functions that use it.

Third-party resources

As other developers create utilities integrating with FairCom DB, FairCom assigns resource identifiers when necessary.

Resource Identification

Within a given data file, a Resource is identified by three elements.

Resource Element

Data Type

Type

unsigned long integer

Number

unsigned long integer

Name

null terminated string

Within each file, you can identify a Resource by its unique combination of Type and Number, or by its Name.

Note: The Resource Name is not guaranteed to be unique.

Resource Type

Resource Type gathers Resources into related groups. Resource Types in the range of 1 to 127 are reserved for use by FairCom. These are special Resources used by the FairCom DB, r-tree Report Generator, the d-tree application builder, FairCom DB API, and FairCom DB SQL. Resource Types in the range of 128 to 65536 are also reserved and are explicitly assigned to third party developers by FairCom. Resource Types numbered 65537 and above are available to any developer and can be assigned as desired.

Resource Number

There are no restrictions on assigning Resource Numbers. They separate various Resources within a given Resource Type. When adding a Resource to a file, FairCom DB can assign the next available value for this Resource Type in the referenced table.

Resource Name

You can use the Resource Name as a way to access Resources in a file instead of using the Type and Number. This can make application code more readable if you use a symbolic name rather than a pair of numbers. If you are adding a number of Resources to a data file over a period of time you may not know what Resource Number has been used, particularly as FairCom DB can automatically assign the next available Resource Number. Access via Resource Name is simpler than keeping track of what Resource Number has been assigned.

However, use caution when assigning Resource Names. FairCom DB cannot guarantee that each Resource Name is unique within a table. It is possible to add a duplicated Resource name to a table.

Resource Names are optional. They are not required for a Resource. The Resource Name is a null terminated character string of any length. FairCom recommends you do not make them too long. Resource Names starting with the character sequence "FC!" are reserved for use by FairCom. Resource Names starting with with the character sequence "RD!" are reserved for Resources assigned to third party developers by FairCom.

FairCom DB API C++ API - Working with Resources

Resource operations are usually performed in the following sequence:

  1. Instantiate a CTResource object by calling one of the CTResource constructors.
  2. Perform the desired operation such as adding, updating, deleting or reading resources
  3. Once the CTResource object is no longer needed, destroy the object to release any system resources.

Constructing Resource Objects

Before any operations can be performed on resources, you are required to instantiate a resource object. There are three overloaded CTResource constructors:

CTResource::CTResource(const CTTable& hTable);

Construct a CTResource object with the resource type and number set to zero and the resource name set to NULL.

CTResource(const CTTable& hTable, ULONG type, ULONG number);

Construct a CTResource object passing the resource type and number. The resource name is set to NULL.

CTResource(const CTTable& hTable, ULONG type, ULONG number, const CTString& name);

Construct a CTResource object passing the resource type and number, as well as the resource name.

Example

void DisplayAllResources(const CTTable& hTable)

{

CTResource* hRes = new CTResource(hTable);
 

try

{

// get the first resource

if (hRes->First())

{

do

{

// display resource type, number and name

printf("Resource type: %u, number: %u",

hRes->GetType(), hRes->GetNumber());

}

while (hRes->Next());

}

}

catch (CTException &err)

{

printf("Error %d - %s\n", err.GetErrorCode(), err.GetErrorMsg());

}

delete hRes;

}

Adding New Resources

When adding a Resource to a table, a special variable-length record is written to the table, containing the information from the Resource Data Block. This is done even if a data file uses fixed-length records. Every Resource is identified by a unique combination of a Resource Type and a Resource Number. The Resource Number can optionally be assigned by c-tree Plus during the call to CTResource::Add() method. In addition, each Resource can be identified by a Resource Name. The Resource Name is not guaranteed to be unique.

The following steps are required to add a new resource to a table:

  1. Instantiate a CTResource object by calling one of the CTResource constructors. You should pass at least the resource type and number. The resource name is optional. If you use a CTResource constructor that does not take the resource type and number, you need to call CTResource::SetType() and CTResource::SetNumber() to set the resource type and number before you add a new resource.
  2. Call CTResource::Add() method to add the new resource passing the resource data and the length of the data.
  3. Once the CTResource object is no longer needed, destroy the object to release any system resources.

To add a new resource you must call the following CTResource class method:

void CTResource::Add(pVOID data, VRLEN size);

data is any collection of data that you wish to store as a Resource. This can be a character string, a structure, or any variable type. size indicate the number of bytes occupied by data parameter value.

The Resource Type must be a value greater than 65536. 0 through 65536 are reserved for FairCom use. If the Resource Number is a value of CTDB_ASSIGN_RESOURCE_NUMBER (0xffffffff), c-tree Plus assigns this Resource the next available Resource Number for this Resource Type in the specified data file. The assigned number can be retrieved by calling CTResource::GetNumber() method before the resource object is destroyed. The Resource Name is optional. c-tree Plus does not guarantee unique Resource Names. Names starting with the character sequence "FC!" or "RD!", are reserved for FairCom use.

Example

void AddMyResource(const CTTable& hTable, ULONG type, const CTString& name, pVOID data, VRLEN size)

{

CTResource* hRes = new CTResource(hTable, type, CTDB_ASSIGN_RESOURCE_NUMBER, name);

try

{

hRes->Add(data, size)

printf("Resource added with number %u\n", hRes->GetNumber());

}

catch (CTException &err)

{

printf("Error %d - %s\n", err.GetErrorCode(), err.GetErrorMsg());

}

delete hRes;

}

Deleting Resources

The following steps are required to delete a resource from a table:

  1. Instantiate a CTResource object by calling one of the CTResource constructors. You should pass at least the resource type and number. The resource name is optional. If you use a CTResource constructor that does not take the resource type and number, you need to call CTResource::SetType() and CTResource::SetNumber() to set the resource type and number before you add a new resource.
  2. Call CTResource::Delete() method to delete the resource
  3. Once the CTResource object is no longer needed, destroy the object to release any system resources.

A resource can be deleted from a table by calling the following CTResource class method:

void CTResource::Delete();

Example

void DelMyResource(const CTTable& hTable, ULONG type, ULONG number)

{

CTResource* hRes = new CTResource(hTable, type, number);

try

{

hRes->Delete();

}

catch (CTException &err)

{

printf("Error %d - %s\n", err.GetErrorCode(), err.GetErrorMsg());

}

delete hRes;

}

Updating Existing Resources

The following steps are required to update a resource:

  1. Instantiate a CTResource object by calling one of the CTResource constructors. You should pass at least the resource type and number. The resource name is optional. If you use a CTResource constructor that does not take the resource type and number, you need to call CTResource::SetType() and CTResource::SetNumber() to set the resource type and number before you add a new resource.
  2. Call CTResource::Update() method passing the resource data and the size in bytes of the resource data.
  3. Once the CTResource object is no longer needed, destroy the object to release any system resources.

An existing resource can be updated by calling the following CTResource method:

void Update(pVOID data, VRLEN size);

The Resource data is any collection of data that you wish to store as a Resource. It can be a character string, a structure, or any variable type. size indicate the number of bytes occupied by data.

Example

void UpdateMyResource(const CTTable& hTable, ULONG type, ULONG number, pVOID data, VRLEN size)

{

CTResource* hRes = new CTResource(hTable, type, number);

try

{

hRes->Update(data, size);

}

catch (CTException &err)

{

printf("Error %d - %s\n", err.GetErrorCode(), err.GetErrorMsg());

}

delete hRes;

}

Reading Resources

Essentially, there are four different methods to read resources from a c-tree Plus table. Read all table resources, read all resources starting past a resource type and number, read a specific resource by specifying the Resource Type and Resource Number, or read a resource by specifying a Resource Name. Described below are examples of each method.

Read all c-tree Plus Resources from a Table

Read all resource starting with the first resource by calling method CTResource::First() and then read the remaining resources by calling method CTResource::Next(). To read the first resource in a table, call the following CTResource method:

CTBOOL CTResource::First(CTBOOL lock = NO) const;

CTResource::First() retrieve the first resource stored in a table.

  • lock is used to indicate if the resource should be locked, if it is found.

CTResource::First() returns YES if the resource was found or NO if no resource was found. If an error is detected, CTResource::First() throws a CTException exception.

To read all other resources of a table call the following CTResource method:

CTBOOL CTResource::Next(CTBOOL lock = NO) const;

CTResource::Next() retrieves the next resource stored in a table, after a successful call to CTResource::First() is made.

  • lock is used to indicate if the resource should be locked, if it is found.

CTResource::Next() returns YES if the resource was found or NO if no resource was found. If an error is detected, CTResource::First() throws a CTException exception.

Example

void DisplayAllResources(const CTTable& hTable)

{

CTResource* hRes = new CTResource(hTable);

 

try

{

// get the first resource

if (hRes->First())

{

do

{

// display resource type, number and name

printf("Resource type: %u, number: %u",

hRes->GetType(), hRes->GetNumber());

}

while (hRes->Next());

}

}

catch (CTException &err)

{

printf("Error %d - %s\n", err.GetErrorCode(), err.GetErrorMsg());

}

delete hRes;

}

Read all c-tree Plus Resources Given a Starting Point from a Table

Read all resources starting from a given resource type and number by calling method CTResource::Next(). Start by instantiating a resource object setting the resource type and a resource number and then call CTResource::Next(). In this case a resource is found if its type is greater or equal to the specified type and its number is greater than the specified number.

Example

// read resources with type >= type and number > 0

void DisplayResources(const CTTable& hTable, ULONG type)

{

CTResource* hRes = new CTResource(hTable, type, 0);
 

try

{

while (hRes->Next())

{

printf("Resource type: %u, number: %u",

hRes->GetType(), hRes->GetNumber());

}

}

catch (CTException &err)

{

printf("Error %d - %s\n", err.GetErrorCode(), err.GetErrorMsg());

}

delete hRes;

}

Read a Specific Plus Resources from a Table

Read a specific resource by providing exact resource type and number by calling CTResource::Find():

CTBOOL Find(ULONG type, ULONG number, CTBOOL lock = NO) const;

Locates and retrieves a resource in a table based on type and number.

  • type is a value of the resource type.
  • number is the value of the resource number to be located.
  • lock is used to indicate if the resource should be locked, if it is found.

CTResource::Find() returns YES if the resource was found or NO if this particular resource was not found. If an error occurs, CTResource::Find() throws a CTException exception.

Example

// display a particular resource

void DisplayResource(const CTTable& hTable, ULONG type, ULONG number)

{

CTResource* hRes = new CTResource(hTable);
 

try

{

if (hRes->Find(type, number))

{

printf("Resource type: %u, number: %u, name: %s\n",

hRes->GetType(), hRes->GetNumber(),

hRes->GetName().c_str());

}

else

printf("Resource %d,%d not found\n", type, number);

}

catch (CTException &err)

{

printf("Error %d - %s\n", err.GetErrorCode(), err.GetErrorMsg());

}

delete hRes;

}

Read a c-tree Plus Resources by Name from a Table

Read a resource by providing its name by calling CTResource::Find():

CTBOOL CTResource::Find(const CTString& name, CTBOOL lock = NO) const;

CTResource::Find() locates and retrieves a resource by name. c-tree Plus cannot guarantee unique resource names.

  • name is the resource name being located.
  • lock should indicate if the resource should locked, if it is found.

CTResource::Find() returns YES if the resource is located or NO if no resource is located. If errors are detected a CTException exception object is thrown.

Example

// display a particular resource by name

void DisplayResource(const CTTable& hTable, const CTString& name)

{

CTResource* hRes = new CTResource(hTable);
 

try

{

if (hRes->Find(type, name))

{

printf("Resource type: %u, number: %u, name: %s\n",

hRes->GetType(), hRes->GetNumber(),

hRes->GetName().c_str());

}

else

printf("Resource %s not found\n", name.c_str());

}

catch (CTException &err)

{

printf("Error %d - %s\n", err.GetErrorCode(), err.GetErrorMsg());

}

delete hRes;

}

Get and Set Resource Properties with the FairCom DB API C++ API

A number of methods are provided to enable the getting and setting of resource object properties. The table bellow describe each function:

FairCom DB API Resource C++ API Function

Description

CTResource::GetType

get the resource type

CTResource::SetType

set the resource type

CTResource::GetNumber

get the resource number

CTResource::SetNumber

set the resource number

CTResource::GetName

get the resource name

CTResourceSetName

set the resource name

CTResource::GetDataLength

get the resource data buffer length in bytes

CTResource::GetData

get a pointer to resource data buffer

CTResource::SetData

set the resource data buffer


Resource Locks

It is expected that you process resource updates without permitting user interactions to occur during the actual update. It is important for performance considerations and FairCom DB API assumes that resource entries will be locked only for very short intervals. Do not lock a resource and then request user input. Be careful not to include resource updates, (additions, deletions or updates), in long held transactions when the table is under transaction processing control. Locks cannot be released until a transaction either commits or aborts.

FairCom DB API resource handling automatically unlocks resources when necessary, however, a resource can be manually unlocked by the user. Use the following function to check if a resource is locked or not:

CTBOOL CTResource::IsLocked() const;

CTResource::IsLocked() returns YES if the resource referenced by the resource handle is locked, otherwise it returns NO. The following method should be used to unlock resources whose locks are no longer necessary:

void CTResource::Unlock();

CTResource::Unlock() releases a lock placed on a resource by one of the following read resource functions: CTResource::First(), CTResource::Next() and CTResource::Find().

FairCom DB API C++ API Resource Locking Example


if (hRes->IsLocked())

hRes->Unlock();