Symbian
Symbian Developer Library

SYMBIAN OS V9.4

Feedback

[Index] [Previous] [Next]


CommsDat API and Migration Guide

[Top]


Contents

[Top]


1 Introduction


1.1 Purpose and Scope

This is a guide to the CommsDat interface. It is also a migration guide for Commdb users. It is intended for use by all Commdb and CommsDat users.

[Top]


2 Overview of CommsDat Design and API

The comms database is a persistent store of the data required to configure comms components or to make connections with remote servers. The data is held in a small set of related tables persisted by a storage server.

The interface to comms data on the device is the CommsDat DLL, which is loaded by a client process and interacts with the data storage server. The storage server API is hidden from the client by an abstract database interface in CommsDat. The storage server in use at the moment is the Central Repository.

CommsDat presents comms configuration data to the client via a set of interface classes that represent the tables in the database. The format of the interface data set does not need to exactly match the format of the data stored on the device, as CommsDat will map between the two schemas. More than one version of the interface classes can be available at one time and CommsDat will map from each different version to the single data format stored on the device. This allows flexibility in data management on the device and protects external clients from backward compatibility issues when changes are required to the data set used by the comms stack.


2.1 Overview of Comms Data Structure

Comms configuration data is stored in a small database of related tables. Each entry, or Element, in the database consists of:


2.2 Overview of the CommsDat API

The CommsDat API provides functions for accessing and manipulating comms configuration data stored in the comms database.

The API has the following main features:


2.3 Overview of the Design of the CommsDat Module

The CommsDat module is a DLL loaded by a client process. It is a mapping and validating interface to the comms database held in a data server. CommsDat is the only interface to the comms database for all comms data users. It maps between one or more client-side representations of the data and the native stored data set.

In addition to an abstract data interface, CommsDat presents an abstract data storage API that does not reveal the API of the data storage server (currently the Central Repository). So CommsDat clients are shielded from future changes in both the comms data format and the comms data storage mechanism.

Beneath the CommsDat API is a mapping layer that transfers data between the set of client-side data formats and the single stored data format, and a validation layer that ensures the integrity of the dataset on the device. Below that is the interface with the storage server.

The following diagram sketches CommsDats structure and its relationship with the client process, the storage server and comms configuration data. Major message flows are shown by dark arrows. Structural design relationships are indicated by dashed lines.



2.4 Migrating from CommDb to CommsDat

CommsDat is a replacement for the CommDb component. The CommsDat API is new, but all central CommDb functionality is still provided by CommsDat.

There are some behavioural differences. In particular, the Commdb SQL API has been removed. The SQL API in CommDb was mainly used to select views of database tables matching particular field values and to create new user-defined tables in the database at run time. This functionality is retained. Selection of sets of records can be performed by pattern matching fields in a primed Container class with records in the database. New tables can be defined and stored with the CMDBGenericRecord class.

During the migration period a shim component will be available in place of CommDb. The CommDbShim presents the CommDb API and behaviour unchanged except for the removal of the SQL API. The shim interacts with CommsDat to access the comms database.

Section 9 below discusses issues in the migration and recommends ways to make the most efficient use of CommsDat.

[Top]


3 Comms Data Format

Comms data is stored in table format. A Table has a name and a numeric Id and defines a set of named and numbered Columns of values of a specific data type. Data Fields are stored under these Columns and grouped together into Records. A group of CommsDat Records of the same Table type is referred to as a Table or a Record Set.

Each Table, Record, Column or Field is referred to as a CommsDat Element and has an Id, a set of access control Attributes and a Value of a particular type. Within CommsDat these are presented by a set of classes that are described here.


3.1 CMDBElement

CMDBElement is the base class that defines all Elements that can be stored in the database. The class and the set of Containers that derive from it encapsulate the three components of an Element - its Id, access control attributes and its value.

CMDBElement inherits from the class MMetaDatabase that provides an abstract database access interface to interact with the data in the storage server. The MMetaDatabase interface is described in section 5 below.

There are several specialised Container classes representing Tables, Records and Fields that derive from CMDBElement. These classes present the client with a view or cache of data for a specific Element in the Comms Database. Container classes are discussed in section 4 below.

The CMDBElement class provides functions to manipulate the Element Id and Attributes of an Element

3.1.1 ElementId

CMDBElement functions allow manipulation of the Element Id, which is expressed as a class

TMDBElementId

This describes the Elements

TypeId - The Table and Column id of the Element

RecordId - The Record id of the Element

The location of an Element in the database schema is identified by its Element Id. Thus the meaning of an Element in the database schema is expressed by the Element Id.

The numeric structure of an Element Id is internal to the CommsDat component and this implementation detail of the component is not part of the published API of CommsDat. A set of public constants defined in CommsDat.h is provided to enable clients to understand and manipulate Element Ids.

3.1.2 Attributes

CMDBElement presents functions to get, change or query access control Attribute flags for the Element. Attributes are expressed using the class

TMDBAttributeFlags

3.1.3 Element Value

The value of an Element is stored in CMDBElement class, but is only accessible via derived Container classes. Lookup tables holding schema details map an Elements Id with its value type.


3.2 Data Security in the Storage Server

Data in the comms database is protected by platform security capabilities that are policed by the data storage server. Depending on assigned capabilities, a client process has read or read-write access to some or all of the Elements in the database.

The current platform security schema is as follows

Default read capability

None

Default write capability

WriteDeviceData

Reading (or writing) private user data such as user names or passwords

ReadDeviceData

Writing protected data such as an Operator-set ISP record

NetworkControl

Clients with the appropriate capability have the ability to change the access control Attributes of comms data Elements. Symbian OS relies on trusted processes with access capabilities to adhere strictly to data access control protocols.

Processes with no capabilities cannot write to the database and so cannot disturb the data integrity of the Comms Data Set either via the CommsDat API or by attempting to manipulate data directly in the storage server. A client must also have WriteDeviceData capability to use database functions such as opening a transaction to write to the database. The platform security schema ensures that clients with no capability cannot deny usage of the database to other clients.

3.2.1.1 Element Attribute Flags

The access level of an Element is indicated by the set of Attribute flags that are set against it. All Attributes can only be set or cleared in the database by clients with the WriteDeviceData platform security capability at a minimum and some require additional capabilities.

The enumeration

TCDAttributeFlags

declared in CommsDat.h defines four access control attribute flags.

ECDNoWriteButDelete

Basic read only guard included for backwards compatibility with CommDb. No additional platform security for this attribute.

ECDHidden

Specifies whether or not to display this Element. No additional platform security for this attribute.

ECDPrivate

Hides private user data such as username or password fields. The ReadDeviceData capability guards database read and write calls to Elements that have this flag set.

ECDProtectedWrite

Protects Elements from being written by most processes. Set and cleared as part of Commdb Protection API. The NetworkControl capability guards database write calls to Elements that have this flag set, but all clients can read Protected data.

The ECDHiddenand ECDNoWriteButDelete attributes are not enforced by additional platform security other than the default WriteDeviceData that guards all write operations. The ECDNoWriteButDelete flag is considered obsolete but is included for backwards compatibility with Commdb settings.

Platform security settings in the storage server are cumulative, so successfully updating a Private and Protected Element in the database would require the setting of the ECDPrivate and ECDWriteProtected flags in the CommsDat Element Container class; and would depend on the client process having WriteDeviceData, ReadDeviceData and NetworkControl capabilities when it called the database storage function.

3.2.1.2 Session Attribute Mask

Attribute flags set the access control level required by each Element stored in the database, but the access control permissions that a CommsDat client wants to use are set using the SetAttributeMask in the CMDBSession class found in metadatabase.h.

To remove a viewing or writing restriction required by an Attribute Flag on an Element without changing the Elements access control level for all users, a client should Set the Attribute Mask for that Flag. So, to view hidden records, a client should set the attribute mask for ECDHidden . This will make all Elements with the ECDHidden flag visible to the client during that session. A mask can be cleared again using the ClearAttributeMask function.

Setting an Attribute Mask does not remove platform security checks, however. So, for example, a client process without NetworkControl capability would never be able to write to Elements protected with ECDProtectedWrite, even if the mask were set for this flag via the session API. Setting the Attribute Mask does not make a call to the database server or check client capabilities and the function will not fail.

The default mask settings ensure that every access control attribute restriction is obeyed.

See section 5 for more information about the Attribute Mask functions.

3.2.2 Data Set Versioning

CommsDat introduces the possibility of Comms Data Set interface versioning that was not available with CommDb.

Allowing multiple versions of client-side data set protects clients from backward compatibility issues inherent in inevitable periodic changes to comms configuration information. New data set versions may be introduced from time to time, in which case older data set versions will be deprecated, but supported for a managed period of time.

[Top]


4 Container Classes

To allow preparation, storage and manipulation of comms data in the client process, CommsDat provides a set of Container classes. Each of the Container classes represents an Element in the database and inherits from CMDBElement, which in turn inherits from the database access interface class, MMetaDatabase to allow easy interaction with the database. This is a summary of the container classes and their function

Representation of Comms data records:

CMDBRecordBase

a base class to represent any record

CCDRecordBase

a base class for records with named field members. Inherits from CMDBRecordBase

CMDBGenericRecord

a class representing a record from a table that is defined by the client at run time and not known at compile time to CommsDat. Inherits from CMDBRecordBase.

CMDBRecordLinkBase

a base class for CMDBRecordLink<T>

CMDBRecordLink<T>

This class expresses a soft-link from a field in one record to a record of a different type <T> in another table

Representation of a Comms Data Table

CMDBRecordSet<T>

An array of records where T is the record type. This represents a Table in a database.

Representation of Comms data field

CMDBFieldBaseXXX

A set of base class for fields of different basic types.

CMDBField<T>

where T is a basic type value of the field ( TInt, TDesC, TBool etc). These classes each inherit from an appropriate CMDBFieldBase class.


4.1 Scope of Container function calls

All function calls in the CMDBElement class and the Containers that inherit from it perform actions local to the Containers themselves and the data they encapsulate. None of these functions interacts with other mapping or validation classes inside CommsDat or with the underlying database.

To use the mapping, validation and database access functionality in CommsDat a client must call functions from the MMetaDatabase interface.


4.2 Creating a CommsDat Container Object

All CommsDat Container objects should be created on the Heap and deleted explicitly as they inherit from CBase.

CMDBRecordBase classes should always be created by a call to the factory function

IMPORT_C static CMDBRecordBase* RecordFactoryL(TMDBElementId);

Or copied from another instance with the copy function

IMPORT_C static CMDBRecordBase* CreateCopyRecordL( 
        CMDBRecordBase&
        aCopyFromRecord);

4.3 Getting and Setting Data in Containers

A Container class gives a view of part of the database and provides a cache of comms database information in the client process.

4.3.1 Getting data from a Templated Field Container

An overloaded conversion operator will automatically convert the data value in a CMDBField class to the templated type. This allows a CMDBField object to be used as the right-hand side argument in assignment calls or to be passed directly into functions requiring items of the templated type.

To check whether the field has a NULL value, either check the IsNull() function before using the conversion operator or use the GetL() call instead of the conversion operator. This will leave if the field value is NULL.

The value of a field in a Container will be NULL if it has not yet been set by the caller and has not yet been loaded from the database. If it is NULL after being successfully loaded from the database a field has been explicitly set to NULL by the writer of the record.

4.3.2 Setting data in a Field Container

Use the assignment operator to add data to a field. A field of type T will accept an item of type T as the right-hand argument of an assignment call.

Setting descriptors needs a further preparatory call to set the size of the fields buffer. First call SetMaxLengthL() with the length of the string to be added and then call the assignment operator. Calling the assignment operator for a descriptor field will have no effect unless the buffer length has been set to an appropriate size.

Alternatively the SetL() call can be used. This function will calculate the length of a descriptor parameter for a descriptor field type and perform the allocation and assignment together, leaving if there is an error.

4.3.3 Getting and Setting data in a CCDRecordBase Container

Data in a CCDRecordBase Container is accessed by interacting with each of the named member Fields individually as described above. Fields in a CCDRecordBase class are public and are normal data members of the class.

Alternatively, fields can be retrieved using the following functions:

GetFieldByNameL
GetFieldByIdL

The GetFieldByNameL function should be used as little as possible as it has to use expensive descriptor comparison. It is provided only for backward compatibility with the CommDb interface.

It is more efficient to use GetFieldByIdL which looks up Fields in a Record Container by their TypeId. It is most efficient to access the field directly in a specialised CCDRecordBase class where the type of the Element is stated at compile time.

4.3.4 Accessing Fields in a Generic Record Container

The CMDBGenericRecord class that is used to define and access user-defined Tables in the database cannot have named Field members as the Field identity cannot be known at compile time. So for this class, Field access is exclusively via the GetFieldByNameL and GetFieldByIdL functions.

Unlike the CCDRecordBase versions of these functions - which make use of static lookup tables to iterate through the data field members in the Record and to establish their Name, id or Field type - the CMDBGenericRecord versions rely on a Table schema supplied explicitly at Run-time. A client can initialise the Container with a Table Schema via the InitialiseL function or the schema can be retrieved from the database via LoadL or FindL functions.

4.3.5 Accessing Records in a RecordSet Container

In a Record Set ( CMDBRecordSet), CMDBRecordBase classes are stored in a public RArray member and can be accessed using normal RArray interface functions.

4.3.6 Accessing Fields From a Linked Record in a CMDBRecordLink Container

A CMDBRecordLink container is first an integer field. The data and element id of the linking field can be accessed in the normal way as for other CMDBField classes.

The data in the Linked Record is accessed in the normal way via the member

CMDBRecordBase * iLinkedRecord

Sometimes it is known at compile time what Table Type this record will be, in which case a client can cast the record to the appropriate sub-class and access the data via member name.

When the type of the record is not known at compile time a client should first establish the Element Id of the linked record and then perform an appropriate down cast or simply access the data via the base class using GetFieldByNameL or GetFieldByIdL.


4.4 Preparing a Container for interaction with the database

A client may need to prepare an Element Container object before interaction with the database. This may involve setting field values, the Record Type Id or the Record Id and perhaps setting access control Attribute flags.

4.4.1 Preparing Field Values

If data needs to be stored or modified in the database it must first be added or modified in the Container.

Using the FindL function requires one or more Fields in a Record to be primed with values to allow pattern matching with records in the database see section 5.4.2 below on the FindL function.

Field values do not need to be prepared before calls to LoadL, RefreshL or DeleteL.

4.4.2 Preparing Type information

The Table Id of an Element must always be given before any database call. The Table Id must be known in every case except when asking to find a user-defined Table given a Table name, in which case the Type Id should be zero, or when attempting to store a new Table with a CMDBGenericRecord, in which case the Element Id should be set to the constant KCDNewTableRequest (Note: this API is only available to device creators) and it will be then be returned as a new value by CommsDat once the table has been created in the database.

4.4.3 Preparing the Record Id

The Record Id of an Element is set with the CMDBElement function

SetRecordId()

The Record Id must always be set before all MMetaDatabase calls except FindL, which matches instantiated field values to establish the Record Id.

When storing a new record the client must either set the Record Id explicitly (assuming it can establish an Id that does not already exist) or set the Record Id to the constant KCDNewRecordRequest which will cause the new Record to be given the next available Record Id in the Table when it is stored in the database.

4.4.4 Preparing Attribute Flags

Access control Attributes of an Element need only be set if they are different from the default settings. If a record is hidden or protected, this must be specified before any call except FindL and LoadL.

Before a call to a MMetaDatabase function, the client must also ensure that the general attribute mask is appropriate for the desired access level, by setting or clearing the attribute mask via calls in the CMDBSession instance. CommsDat will not read or write Elements that have Attribute flags other than those explicitly Set in the Attribute Mask.


4.5 Using Containers efficiently

A CommsDat Container should be regarded as a cache of database information in the client process. The Containers have been designed to make it easy for a client to retrieve just the data required from the database with minimal overhead in terms of memory and speed.

A developer should always use the smallest Container available that will provide the information that is needed. Loading only one field from a record where the Table, Column and Record id are known can be done using a single CMDBField Container. Similarly, it is not necessary to load a full record set to access a single record.

Using linked records can reduce the amount of code required to access records across a set of linked tables.

Careful use of the FindL function can restrict the size of Record Sets retrieved from a stored Table to just the specific records required by the client in the same way that a DBMS client can use an SQL Select statement to restrict the size of a table view.

Many routines accessing the comms database have the goal of accessing a single field, but need to access one or more records first to establish the id of the target Field. In this kind of usage a Record Container may be needed to do the FindL call to establish the target Element Id, but the target field itself can be accessed with a single CMDBField class primed with the retrieved Element Id.

[Top]


5 Data Storage API - Interaction with the Database

To interact with the database, a session must be created via the class CMDBSession. The session object is then used as a handle to a session with the data storage server when using database access functions in the MMetaDatabase class.


5.1 Session Creation and Data Set Versioning

As comms data can be presented to CommsDat clients in different data set versions, CommsDat session creation requires the user to specify which version is needed.

A client willing to upgrade to new data set version as it becomes available should create a session using the latest version as specified by the KCDLatestVersion constant in CommsDat.h. Clients that would prefer to continue to use a specific data set and need to be protected from data compatibility changes in later versions should name a version explicitly. CommsDat will then map stored data to and from that representation, as long as the requested version is still supported in Symbian OS.


5.2 Transactions

CMDBSession contains transaction functions to ensure consistent reads and atomic data entry in the database.

OpenTransactionL
CommitTransactionL
RollbackTransactionL

A transaction can be opened in ReadOnly or ReadWrite mode. The storage server enforces the transaction model.

5.2.1 CommsDat Transaction Behaviour

Transaction behaviour is implemented in the Storage Server. The CommsDat interface guarantees only that

Other aspects of transaction behaviour such as the timing of the obtaining of a write lock during a read/write transaction or the reasons for transaction failure are implementation details of the storage server and should not be relied on as part of the CommsDat interface by CommsDat clients.

5.2.2 Using CommsDat Transactions

All MMetaDatabase read and write functions are performed using internal transactions and are therefore consistent and atomic in their own right.

Clients should open write transactions sparingly and should be careful not to hold a transaction open for a long time it locks the database against writes by other sessions.

It can be more efficient to wrap several write operations inside one transaction as data only gets persisted on Commit, but clients should be careful not to hold a transaction open for longer than necessary.

MMetaDatabase functions using linked records are atomic across two or more tables without the need for a client to set a transaction explicitly (see section 4 above).

5.2.3 Client Responsibilities regarding CommsDat Transactions

As with Commdb, clients must ensure that they keep transactions as short as possible as the comms database is used by many other processes.

Very long running transactions may be terminated with a timeout in order to protect the Comms database from deadlock or a denial of service attack. This is a change in behaviour from CommDb. However, this timeout will not affect normal operation.


5.3 Data Access control

The CMDBSession functions

SetAttributeMask(TMDBAttributeFlags aAttributeFlags)
ClearAttributeMask(TMDBAttributeFlags aAttributeFlags)

allow the client to specify which of the access control Attribute flags they wish to enforce depending on the clients platform security capabilities. Any access control flag in an Element is ignored while the mask for it is Set and is obeyed while the mask for it is Cleared. If a client process asks to set or clear an access control flag that requires higher capabilities than it has been granted, the request itself will not fail (these calls do not go through to the storage server), but the request will not have any effect since access to the Element in question will be denied anyway by the policing storage server.

5.3.1 Support for Commdb Hidden and Read Only Fields

The Attribute Mask functions should be used to ask to show (or hide) Hidden records as for Commdb and can also be used to ask to ignore or obey read only but deletable Attributes.

5.3.2 The Commdb Protection API

The Attribute Mask functions can be used to ignore or obey the read-only Protection flag that used to be set by the (private) Commdb Protection API. To Protect or Unprotect a record is an operation reserved for a small set of users and this functionality is guarded with NetworkControl capability. For users that do not have this capability, setting or clearing the ECDProtectedWrite flag will have no effect as the Storage Server will always enforce platform security settings on all write calls to Protected Elements.

To Protect a record a client should:

  1. Create a Container of the appropriate type and set the Element and Record Id as necessary to identify the target Element in the database.

  2. Set the Attribute Flag at the highest appropriate level in the Container to ECDProtectedWrite (this setting will then propagate down through each Element in the Container)

  3. Set the Attribute Mask in the session to ECDProtectedWrite

  4. Call ModifyL on the Container (or StoreL if the element is being stored for the first time).

  5. Clear the ECDProtectedWrite Attribute Mask in the session.

To unprotect an element the same procedure should be followed but the client should Clear the Attribute flag in the element at step 2.

Its not necessary to Load the data for an element from the database before changing its Attributes with ModifyL.


5.4 Interaction with the data in the database

The class MMetaDatabase is an interface for manipulating data within the database. It provides functions to read data ( LoadL, FindL, RefreshL), to write data ( StoreL, ModifyL, DeleteL) and functions to register for notification of changes in the database.

All CommsDat Containers derive from the MMetaDatabase class. So database access functionality is automatically built into each data Container. Once data has been prepared in the Container, interaction with the database is performed by calling one of the MMetaDatabase functions available in the Container interface.

This section describes the operation of each MMetaDatabase function in turn.

5.4.1 LoadL

Loads data from the database into the Container according to the specified Element Id.

This function loads the data for the requested Element from the database into the Container. Only data that the client has capabilities to view and that has had any read-protection cleared in the session's Attribute Mask will be returned. LoadL will overwrite any data that already exists in the Container with data retrieved from the database.

The function will leave if CommsDat or the Storage Server return errors. It will leave with KErrPermissionDenied if the client explicitly requests to load an Element for which it does not have platform security capabilities, but will silently ignore inaccessible records within a requested table or inaccessible fields within a requested record.

A LoadL call will open a read-only transaction with the storage server if the client is not already in a transaction and hence can be guaranteed to be atomic and to give a consistent view of persisted data.

5.4.2 FindL

Find and load data from the database that matches values primed in the Container.

If a client has primed a Record Container with particular values in one or more fields, FindL will attempt to retrieve one or more Records that have matching values in all of those fields.

FindL is a Boolean function returning ETrue if at least one Element containing the requested data is found or EFalse if nothing is found. FindL will not return matching Elements that the client process does not have Platform Security Capabilies to view, nor will matching Elements be returned that have attributes not explicitly Set in the sessions Attribute Mask.

To find a single Record with particular values a client should call FindL on a primed CMDBRecordBase or CMDBField class. The primed Container will be populated with values from the first matching record found in the database and the Element Id will be set as appropriate. On failure, the primed record will be left unchanged.

To find all Records in a Table that match a primed Record, the client should create a CMDBRecordSet, append a single Record to the record array, primed with appropriate field values, and call FindL on the whole CMDBRecordSet instance. On success, the function will return one or more completed records that contain fields that match the primed fields. The initial primed record will be overwritten by the first record found. On failure the primed record will be left unchanged.

A FindL call will open a read-only transaction with the storage server if the client is not already in a transaction and hence can be guaranteed to be atomic and to give a consistent view of persisted data.

5.4.3 RefreshL

RefreshL updates the data in the client Container and is similar to LoadL except that it will not overwrite Fields that have been temporarily modified by the client. Fields that have not been directly modified by the client will be refreshed from the database. This function is useful when maintaining a client-side cache of comms configuration information.

RefreshL will operate in a read-only transaction with the storage server if the client is not already in a transaction and hence can be guaranteed to be atomic and to give a consistent view of persisted data.

5.4.4 StoreL

StoreL will create new records, columns or tables where required. Only fields that have been explicitly amended by a user will be stored. The function will leave with KErrAlreadyExists if any field it attempts to create in the database already contains data.

The Element Id must be prepared by the client before StoreL is called. It should either be a full id or a request for a new Record, Table or Column using one of the constants in CommsDat.h, in which case the correct Id will be returned by CommsDat when the new element has been created in the database.

A call to StoreL will fail if clients do not have read and write capabilities to set any requested Attribute Flags or if the appropriate Attribute Mask has not been set in the CDMBSession.

StoreL will open a read/write transaction with the storage server if the client is not already in a transaction and hence can be guaranteed to be atomic and to give a consistent view of persisted data.

Any error in the StoreL function will fail the transaction that is in progress.

5.4.5 ModifyL

ModifyL will modify the value or the attributes of the specified Element or set of Elements in the database.

ModifyL will fail if clients do not have read and write capabilities to set or clear the Attribute Flags in the element as requested or if the appropriate Attribute Mask has not been set in the CDMBSession.

ModifyL will not create new Records or Tables, but will store new Fields within a record where they have not previously been entered into the database.

ModifyL will open a read/write transaction with the storage server if the client is not already in a transaction and hence can be guaranteed to be atomic and to give a consistent view of persisted data.

Any error in the ModifyL function will fail the transaction that is in progress.

5.4.6 DeleteL

DeleteL will delete the requested Element or a set of Elements from the database. The function will leave with KErrPermissionDenied if clients do not have appropriate read and write capabilities for all Elements in the database indicated by the deletion request. It will also Leave if the client has not correctly set the attribute mask to cover all items to be deleted.

DeleteL will open a read/write transaction with the storage server if the client is not already in a transaction and hence can be guaranteed to be atomic and to give a consistent view of persisted data.

Any error in the DeleteL function will fail the transaction that is in progress.


5.5 Template Records

Commsdat supports the idea of a template record. A template record contains default values which are used if the corresponding column in a specific record has a NULL value.

The DIAL_OUT_ISP table is an example: each record in the table corresponds to an ISP that can be used to make an Internet connection. While the amount of information for each ISP is large, much of it may be common to all the ISPs, and can be held in the single template record. Each ISP record then need only define the information that is specific to that record. If, for a given ISP, the default value for a specific piece of information is sufficient, then that column in that ISP's record is NULL.

To create a record that uses the template, set the recordId to KCDDefaultRecord. A user is able to modify a default attribute for a field type, but this will typically only be done prior to the ROM build by using the CommsDat tools.

To load a template record of CCDNetworkRecord
//Create a Session and set the mask to Hidden to enable viewing template records
CMDBSession *cmdbSession = CMDBSession::NewL(CMDBSession::LatestVersion());
cmdbSession->SetAttributeMask(ECDHidden); 

//STORE:  create a container and set the record id to defaultrecord
CCDNetworkRecord* ptrNetworkRecord =
        (CCDNetworkRecord*)CCDRecordBase::RecordFactoryL(KCDTIdNetworkRecord);
ptrNetworkRecord->SetRecordId(KCDDefaultRecord);
ptrNetworkRecord->SetAttributes(ECDHidden); //template records have to be set to hidden
ptrNetworkRecord->StoreL(*cmdbSession);

//LOAD: create a container and set the record id to defaultrecord
CCDNetworkRecord* ptrNetworkRecord = 
    (CCDNetworkRecord*)CCDRecordBase::RecordFactoryL(KCDTIdNetworkRecord);
ptrNetworkRecord->SetRecordId(KCDDefaultRecord);
ptrNetworkRecord->LoadL(*cmdbSession);

[Top]


6 Client Representation of the Comms Data Set

A set of classes derived from CCDRecordBase provides a convenient representation of the current data set to users. These classes give a simple interface allowing the client to get and set values in the Container as though dealing with a simple class or struct.

These data type classes provided by CommsDat must be created via a Factory function.

IMPORT_C static CMDBRecordBase* RecordFactoryL(TMDBElementId);

Or copied from another instance with the copy function

IMPORT_C static CMDBRecordBase* CreateCopyRecordL(CMDBRecordBase&
      aCopyFromRecord);

Each CCDRecordBase class implements a constructor that takes a TMDBElementId parameter, a macro that defines some internal access functions ( EXP_DATA_VTABLE or DATA_VTABLE) and has a function that allows lookup of type and name information for each of the record's nested Elements in a static table:

const SRecordTypeInfo* GetRecordInfo()
{
    return iRecordInfo;
}

The SRecordTypeInfo table defines the type, name and length of a database Field and states whether or not the Field value can be NULL.

[Top]


7 User-defined Tables

User-defined Tables can be created, stored and accessed as for all native CommsDat Tables, but user-defined data is not fully supported or maintained by Symbian, although it is backed up and secured with platform security in the same way as Symbian comms data.

To create user-defined table in the Comms Database the client should use the CMDBGenericRecord class.

To access user-defined tables a client can either use the CMDBGenericRecord class or can define a new CCDRecordBase class which should be a little more efficient.

New tables should be created using the KCDNewTableRequest constant to ensure their id is unique and does not clash with existing user-defined tables in the database.

See section 12 for examples showing how to create and access user-defined tables.

[Top]


8 Utilities

The Utilities interface provides support for a small set of CommDb utility functions and constructs that gather comms data for specific use cases and present it in a particular way.

All of these functions could be implemented in client processes as they are not central to CommsDat functionality. They remain in the API for backwards compatibility with CommDb. The intention is that over time these functions will be deprecated where possible and the API will eventually be removed.

/*
Set `aDialString` to be the appropriate string based on the
directory number, where the dial is being performed and the
chargecard to use. `ResolvePhoneNumberL()` opens a comms database
to perform the resolution
*/
IMPORT_C static void ResolvePhoneNumberL(TDesC& aNumber,
TDes& aDialString,
TParseMode aDialParseMode,
TUint32 aLocationId,
TUint32 aChargecardId);
/*
Set `aDialString` to be the appropriate string based on the
directory number, where the dial is being performed and the
chargecard to use
@publishedAll
*/
IMPORT_C static void ResolvePhoneNumberFromDatabaseL(TDesC& aNumber,
TDes& aDialString,
TParseMode aDialParseMode,
TUint32 aLocationId,
TUint32 aChargecardId);

CommsDat also includes the header file CommdbConnPref.h to allow inclusion of

TCommDbConnPref

and other related constructs. These Containers are currently exported and implemented by the CommdbShim. They are needed as they are part of the Esock RConnection API. When the shim is removed, these constructs will be moved to CommsDat and supported until they can be deprecated and replaced by CommsDat Containers themselves or until they can perhaps be moved to Esock or some other location.

[Top]


9 Migration Issues

Clients migrating from Commdb to CommsDat should not find the transfer too difficult. However it is worth a little thought to ensure that the use of CommsDat API will be as quick and efficient as possible.


9.1 Referring to Database Elements by Id rather than by Name

The Commdb API presented an interface based on column names. The CommsDat interface allows the client to move away from this inefficient mechanism towards lookup by numeric id and direct access through mapped data objects.

CommsDat does still support the name comparison method of accessing database fields where this is still necessary (for instance via the current Nifman API). However it is strongly recommended that clients use the more direct interface via Element Id wherever possible as this will be more efficient.


9.2 Retrieving small amounts of Data

The CommsDat API makes it possible for clients to be very specific about the information they require from the database.

When migrating calls from Commdb to CommsDat developers may find there is no need to simulate the opening of an entire view using CMDBRecordSet class. Often one or two single CMDBField classes can be used on their own particularly for data retrieval.


9.3 Move towards Record Tags in place of Record Names

Many commdb actions are searches for commdb records by user-defined record name. Such searches would be more efficient if they were done with numeric ids. For this reason a CommsDatTag ( KCDTIdRecordTag) field has been added as well as the Name field ( KCDTIdRecordName). Currently this field is typically filled with the record id of the record to provide backwards compatibility with the CommdbId field, but it can be filled with any numeric record tag.

The CommsDatTag is also a convenient way to link records by specifying a UID as the tag in the records.

[Top]


10 CommsDat Tools

Ced and Ceddump have been ported to use CommsDat rather than Commdb. The client-facing interfaces of these tools remain unchanged and existing Ced files will be processed in the normal way.


10.1 Migrating Ced Files from Commdb

Existing Ced configuration files can still be used with CommsDat as long as the ported version of Ced is called.

To migrate a particular binary instance of a cdbv3.dat DBMS comms database to create a central repository database, a client should first run an older version of ceddump (using an older build with Commdb and Dbms) and then store the output config file for future use with the ported Ced.

It is strongly recommended that clients use the XML interface for Ced. The XML interface performs more validation than the .cfg interface, greatly reducing problems caused by inaccurate configuration files. The .cfg file is now deprecated and will soon be removed in a future release.

[Top]


11 Example Code

Here are a set of examples for typical interaction with CommsDat.

We will use the IAP table for most of our examples here.

****IAP TABLE***
CMDBField<TDesC> iServiceType;
CMDBElementLink<CMDBServiceRecord>  iService;  // Link to a particular Service record
CMDBField<TDesC> iBearerType;
CMDBElementLink<CMDBBearerRecord>  iBearer;    // Link to a particular Bearer record
CMDBElementLink<CMDBNetworkRecord>  iNetwork;  // Link to a particular Network record
CMDBField<TUInt32>  iNetworkWeighting;         // Network weighting
CMDBElementLink<CMDBLocationRecord> iLocation; // Link to a particular Location record

The examples cover the following topics:

  1. Load a table, find the total number of records in the table and sort them by name

  2. Load all IAP records and print each record name

  3. Search for IAP records by their ServiceType, then modify one of the fields in the last record found and store it

  4. Search for an IAP record by its Name, then load the associated service and bearer table

  5. Delete all but the last record from a table

  6. Get an existing record, change a field value and store it as a NEW record

  7. Follow a Link in a Iap record to other tables and get value of the field by both name and ID

  8. Accessing the value of a field by using a CMDBField class instead of loading the entire record

  9. Access control. Load/Store a protected record.

// Headerfiles and namespace

#include <CommsDatTypesV1_1.h>

using namespace CommsDat;

//Creating a session with the latest version

CMDBSession* iDb = CMDBSession::NewL(CMDBSession::LatestVersion());

[OR]

//Creating a session with a particular version

#define KCDVersion1_1 TVersion(1,1,1)

CMDBSession* iDb = CMDBSession::NewL(KCDVersion1_1);

//Set required attributes if any

iDb->SetAttributeMask(ECDHidden);


Eg 1 : Load a table, find the total number of records in the table and sort them by id

// CMDBRecordSet.iRecords is an RPointerArray, Hence the Array Sort can be customized
TInt SortRecordsById(const CMDBRecordBase& aLeft, const CMDBRecordBase& aRight)
{
return (aLeft.RecordId()) < (aRight.RecordId()) ? -1 : 1;
}

//Sort by ID
    
void RecordSort()  
{
CMDBRecordSet<CCDConnectionPrefsRecord>* ptrConnPrefRecordSet = 
   new (ELeave) CMDBRecordSet(KCDTIdConnectionPrefsRecord);
ptrConnPrefRecordSet->LoadL(*iDb);              //The table has been loaded
TInt totalcount = ptrConnPrefRecordSet->iRecords.Count();

// totalcount reflects the total number of records in the Connection Preference table
TLinearOrder<CMDBRecordBase> orderbyId(SortRecordsById); 
ptrConnPrefRecordSet->iRecords.Sort(orderbyId);  
}

EG 2 : Load all IAP records and print the name of each record

void LoadAllIapRecords()
{       
CMDBRecordSet<CCDIAPRecord>*  ptrIapRecordSet = 
   new (ELeave) CMDBRecordSet<CCDIAPRecord>(KCDTIdIAPRecord);
ptrIapRecordSet->LoadL(*iDb);
//The table has been loaded
TInt i(0);
while(i < ptrIapRecordSet->iRecords.Count())
     {
     //RDebug::Print(ptrIapRecordSet->iRecords[i]->iRecordName); 
     i++;
     }
}

EG 3 :Search for IAP records by the ServiceType field, then modify one of the fields in the last record found and store it back

void SearchAllIapRecords()
{
//Create a record set
CMDBRecordSet<CCDIAPRecord>* iapRecordSet = 
   new (ELeave) CMDBRecordSet<CCDIAPRecord>(KCDTIdIAPRecord);
//To find all IAP records supporting DialOutISP service
_LIT(KServiceType, "DialOutISP");
TPtrC Servicetype(KServiceType);
    
//To prime for a search, create a record with the priming fields and append it to the Recordset
CCDIAPRecord* ptrPrimingRecord = static_cast<CCDIAPRecord *>
    (CCDRecordBase::RecordFactoryL(KCDTIdIAPRecord));
ptrPrimingRecord->iServiceType = Servicetype;  
iapRecordSet->iRecords.AppendL(ptrPrimingRecord);    
ptrPrimingRecord = NULL; //since ownership is been passed to the recordset

//Search
if(iapRecordSet->FindL(*iDb))
    {
    //The iapRecordSet->iRecords.Count() will now reflect the number of records found   
    TInt iapRecordsFound = iapRecordSet->iRecords.Count();
    //Lets modify a field in the last record
    CCDIAPRecord* iapRecord = 
        static_cast<CCDIAPRecord*>( iapRecordSet->iRecords [iapRecordsFound-1]);
    iapRecord->iNetworkWeighting = 1;

/*Now store this modified record back to commsdat, 
 ModifyL() will only submit the  changes done by the user
 iapRecordSet->ModifyL(*iDb); will go thorough all the records
 and submit the user changes*/
 
    //to explictly submit only this record
    iapRecord ->ModifyL(*iDb); 
    }
else {
    /* No records found..but iRecords[0] is still present (though will only 
    contain the priming values), so its important to check for the return code */
    }   
}

EG 4 :Search for an IAP record by its Name, then load the associated service and bearer table

void LoadLinkedRecords()
{
//To find an IAP with the following name
_LIT(KMyIap, "NTRas with Null Modem");

//When we search by Name or Id, there can be only one record to be returned
CCDIAPRecord* ptrIAPRecord = 
    static_cast<CCDIAPRecord *>(CCDRecordBase::RecordFactoryL(KCDTIdIAPRecord));
TPtrC recordname(KMyIap);
ptrIAPRecord->iRecordName.SetMaxLengthL(recordname.Length());
ptrIAPRecord->iRecordName = recordname;
//OR    ptrIAPRecord->SetL(recordname);

if(ptrIAPRecord->FindL(*iDb))
    {
    // Found a matching record

/*Now for loading the associated service and bearer tables, iService,iBearer, etc
 are links pointing to other records. These links have a "Value" and "iLinkedRecord".
 The "Value" represent the id of the target field.and gets initialized along with the
 parent record(ptrRecord). When we explictly call load on these LinkedFields,
 "iLinkedRecord" ptr point to the appropriate object. The "iLinkedRecord" ptr is
  owned by the parent record and gets deleted along with it.
  So it has to be set to NULL if the user wants to take ownership.*/
 
    ptrIAPRecord->iService.LoadL(*iDb);
    ptrIAPRecord->iBearer.LoadL(*iDb);

    //Take ownership of the loaded service record cache
    CCDServiceRecordBase* ptrService = 
        static_cast< CCDServiceRecordBase *> (ptrIAPRecord->iService.iLinkedRecord);
    (ptrIAPRecord->iService).iLinkedRecord = NULL;

    /*Deleting ptrIAPRecord also deletes all the loaded iLinkedRecord
    pointers it owns unless set to null*/
    delete ptrIAPRecord;         
    //delete the service view
    delete ptrService;
    }   
}

EG 5: Delete all but the last record from a table

void DeleteRecords()
{
//Load a record set
CMDBRecordSet<CCDIAPRecord>* iapRecordSet = 
    new (ELeave) CMDBRecordSet<CCDIAPRecord>(KCDTIdIAPRecord);
iapRecordSet->LoadL(*iDb);

TInt totalCount = iapRecordSet->iRecords.Count();

/*To exempt one particular record (say the last one) from deletion,
 we should remove it from the list before calling delete on the recordset..*/
CCDIAPRecord* ptrSingleIAPRecord;
if(totalCount > 1)
    {
    ptrSingleIAPRecord = 
        static_cast< CCDIAPRecord *>(iapRecordSet->iRecords [totalCount-1]);
    iapRecordSet->iRecords.Remove(totalCount-1);
    }

//deletes all records except the one we removed
iapRecordSet->DeleteL(*iDb);

//now delete the exempted record anyway
if(ptrSingleIAPRecord)
    {
    ptrSingleIAPRecord->DeleteL(*iDb);
    }   
delete iapRecordSet;
delete ptrSingleIAPRecord;
}

EG 6 :Get an existing record, change a field value and store it as a NEW record

void AddNewRecords()
{

//Load a record set
CMDBRecordSet<CCDConnectionPrefsRecord>* connPrefRecordSet = 
    new (ELeave) CMDBRecordSet< CCDConnectionPrefsRecord >( KCDTIdConnectionPrefsRecord);

TInt totalCount;
connPrefRecordSet->LoadL(*iDb);
    
totalCount = connPrefRecordSet->iRecords.Count(); //Assume TOTALCOUNT = 2

//Case 1: Change the ranking of the first connection pref record

static_cast< CCDConnectionPrefsRecord *> ((*connPrefRecordSet)[0])->iRanking = 3;

/*Set its record id to KCDNewRecordRequest and when we call store,
 the record then gets stored as NEW*/

(*connPrefRecordSet)[0]->SetRecordId(KCDNewRecordRequest);

//Now store this as a new record
(*connPrefRecordSet)[0]->StoreL(*iDb);  //"TOTALCOUNT is now 3"

/*NOTE: Dont call StoreL on the RecordSet unless every 
 record in it are new and needs to be stored*/

//Case 2: Create an empty record and add it to the database

CCDConnectionPrefsRecord* ptrNewRecord2 = 
    static_cast<CCDConnectionPrefsRecord *>
    (CCDRecordBase::RecordFactoryL(KCDTIdConnectionPrefsRecord));

ptrNewRecord2->StoreL(*iDb); //adds a new record  "TOTALCOUNT is now 4"
        
//try storing it again

TRAP_IGNORE(ptrNewRecord2->StoreL(*iDb);) //Will FAIL & Leave TOTALCOUNT is still  4

//set the recordid to KCDNewRecordRequest and store it
ptrNewRecord2->SetRecordId(KCDNewRecordRequest);
ptrNewRecord2->StoreL(*iDb); //Adds a new record "TOTALCOUNT is now 5"

//make a change
ptrNewRecord2->iRanking = 3;
ptrNewRecord2->ModifyL(*iDb); //the change (iRanking only) has been stored
            
connPrefRecordSet->LoadL(*iDb);
totalCount = connPrefRecordSet->iRecords.Count();  //totalCount is 5   
    
}

EG 7 : Follow a Link in a Iap record to other tables and get value of the field by both name and ID

Say the structure of the IAP table is

Record Name

NTRas with Null Modem

Service

NtRas

ServiceType

DialOutIsp

Bearer

...

BearerType

...

Network

...

and in the DialOutIsp table, the record named NtRas says

Record Name

NtRas

Description

Test

Type

.....

DefaultTel

.....

DialResolution

.....

BearerSpeed

9600

.........

So now we need to find out the value of the DefaultTel field by following the link from the IAP table. The example also explains the usage of the GetFieldByNameL and GetFieldByIdL functions.

void GetFieldByNameAndId()

_LIT(KISPType, "DialOutISP");
TPtrC ServiceType(KISPType); 
TUint32 bearerSpeed; 

//create a single IAP record and prime it with the ISP type 
CCDIAPRecord* ptrSingleIAPRecord = static_cast<CCDIAPRecord*>
   (CCDRecordBase::RecordFactoryL(KCDTIdIAPRecord)); 

/* Storage for string or binary fields must be allocated
   explicitly if set or reset by client. Storage required for
storing data
   retrieved from the database is handled by Commsdat.*/ 

ptrSingleIAPRecord->iServiceType.SetMaxLengthL(ServiceType.Length());

ptrSingleIAPRecord->iServiceType= ServiceType; 

//[OR] ptrSingleIAPRecord->iServiceType.SetL(ServiceType); 
if(ptrSingleIAPRecord->FindL(*iDb))
        { 
        //An IAP record with DialOutISP as the service type has
        //been found and loaded 
        
        //Now to load the service table record associated with this IAP 
        
        ptrSingleIAPRecord->iService.LoadL(*iDb);

//Case 1: You know what service type it is

        CCDDialOutISPRecord* ptrIspRecord =
            static_cast<CCDDialOutISPRecord*>(ptrSingleIAPRecord->iService.iLinkedRecord);
        bearerSpeed = ptrIspRecord->iBearerSpeed;

/* Case2: Assume if the service type is unknown OR as a general case

[ IMPORTANT: Both the following functions are more expensive than Case1 ] */

        CCDServiceRecordBase* ptrServiceRecord =
            static_cast<CCDServiceRecordBase*>(ptrSingleIAPRecord->iService.iLinkedRecord);
        CMDBField<TUint32>* field;

//Case 2a: to Find the field by its ID.

        field =
            (CMDBField<TUint32>*)ptrServiceRecord->GetFieldByIdL(KCDTIdBearerSpeed);
        bearerSpeed = *field;

/*Case 2b: To find a field by its name,

[IMPORTANT: GetFieldByNameL is more expensive than GetFieldByIdL and should be avoided where ever possible] */

        TPtrC16 BearerName(KCDTypeNameBearerSpeed);
        TInt valueType; field =
            (CMDBField<TUint32>*)ptrServiceRecord->GetFieldByNameL(
            BearerName,
            valueType);
        bearerSpeed = *field;
        delete ptrSingleIAPRecord; //it also deletes 
                                   // "ptrSingleIAPRecord->iService.iLinkedRecord" 
        }
}

EG 8 : Accessing value of a field by using a CMDBField class instead of loading the entire record

Here we get the value of a field in the GlobalSettings table without loading the entire record

void GetFieldValue()
{
CMDBField<TDesC>* descField = new(ELeave) CMDBField<TDesC>(KCDTIdBearerAvailabilityCheckTSY);
descField->SetMaxLengthL(KMaxTextLength);
descField->SetRecordId(1); //recorded is ALWAYS 1 for global settings table
descField->LoadL(*iDb);
        
if(descField->IsNull())
    {
   //The field is not initialized with a value
    User::Leave(KErrNotFound);
    }
else
    {
    TDesC Value  = *descField;
    }
delete descField;
}

EG 9 : Access control. Load/Store a protected record.

It's preferable to clear the session attribute mask once the access control operations have been completed to safeguard against any unintended writes to access-restricted records.

void StoreProtectedRecord()
{
CMDBSession *iDb = CMDBSession::NewL(CMDBSession::LatestVersion());
    
iDb ->SetAttributeMask(ECDProtectedWrite);

CCDIAPRecord* iapRecord =
static_cast<CCDIAPRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdIAPRecord));
iapRecord->SetAttributes(ECDProtectedWrite); 

iapRecord->StoreL(*iDb);
iDb->ClearAttributeMask(ECDProtectedWrite);
}

        
//Load all hidden records
void LoadHiddenRecords()
{
CMDBSession *iDb = CMDBSession::NewL(CMDBSession::LatestVersion());
    
CMDBRecordSet<CCDIAPRecord>* iapRecordSet = new (ELeave)
CMDBRecordSet<CCDIAPRecord>( KCDTIdIAPRecord);

//Load all IAP records including the hidden records
iDb ->SetAttributeMask(ECDHidden);
iapRecordSet ->LoadL(*iDb); 

//Load non-hidden records only
iDb ->ClearAttributeMask(ECDHidden);
iapRecordSet ->LoadL(*iDb); 

}

[Top]


12 Generic Records

The tables are identified using a name and/or an Id and are created by passing in a Table definition/Schema files


Creating a Generic Table and storing/loading records

//Step 1: Create a schema for the new table

const SGenericRecordTypeInfo recordInfo[] = {
        SGenericRecordTypeInfo(KCDTIdRecordName,EText,ENotNull,KCDTypeNameRecordName),
        SGenericRecordTypeInfo(KCDTIdRecordTag,EUint32,ENoAttrs,KCDTypeNameRecordTag),
        SGenericRecordTypeInfo(KCDTIdWLANServiceId,EUint32,ENoAttrs,KNameWLANServiceId),
        SGenericRecordTypeInfo(KCDTIdWLANType,EUint32,ENoAttrs,KNameWLANType),
        SGenericRecordTypeInfo(KCDTIdWLANEnabled,EBool,ENoAttrs,KNameWLANEnabled),
        SGenericRecordTypeInfo(KCDTIdWLANPriority,EUint32,ENoAttrs,KNameWLANPriority),
        SGenericRecordTypeInfo(0,0,ENoAttrs,KCDNull)
        };

//Step 2: Assign a name for this new table

_LIT(KGenericTable,"MyGenericTable");

//Step3: Create a CMDBGenericRecord object & Initialise it with the name and schema

CMDBGenericRecord* ptrNewTable =
        static_cast<CMDBGenericRecord*>(CCDRecordBase::RecordFactoryL(KCDNewTableRequest));
ptrNewTable->InitialiseL(KGenericTable(),recordInfo);

//Step4: Add a new record to it. You can use GetFieldByNameL or GetFieldByIdL to access a field

TInt valueType; CMDBElement* LanType =
        ptrNewTable-> GetFieldByNameL(KNameWLANType, valueType);
CMDBElement* RecordName = ptrNewTable->GetFieldByIdL(KCDTIdRecordName);

//Step5: Modify the fields and store it (creates a new record)

CMDBField<TUint32>* LanTypefield = static_cast<CMDBField<TUint32>*>(LanType);
CMDBField<TDesC>* RecordNamefield = static_cast<CMDBField<TDesC>*>(RecordName);
*LanTypefield = 100; //say

_LIT(KNewName, " NewName ");
RecordNamefield->SetMaxLengthL(KNewName().Length());
*RecordNamefield = KNewName();
//[OR] RecordNamefield->SetL(KNewName());

ptrNewTable->SetRecordId(KCDNewRecordRequest);
ptrNewTable->StoreL(*iDb);

Load an existing generic record

//Step 1: A generic record is identified by its TableId or a TableName, So create a new object with that type

Case 1: Creating using an Id, when table name is not known

CMDBGenericRecord* ptrTable =
          static_cast<CMDBGenericRecord*>(CCDRecordBase::RecordFactoryL(TableId));

[OR]

Case 2: Creating using an Tablename, when the id is not known

CMDBGenericRecord* ptrTable = static_cast<CMDBGenericRecord*>(CCDRecordBase::RecordFactoryL(0));
ptrTable->InitialiseL(KGenericTable(),NULL);

//Step2: Now set the record ID (say 1) and call LoadL

CMDBSession *dbSession = CMDBSession::NewL(CMDBSession::LatestVersion());
ptrTable->SetRecordId(1);
ptrTable->LoadL(*dbSession);

//Step3: Access a value

CMDBField<TUint32>* field = (CMDBField<TUint32>*)ptrTable->GetFieldByIdL(KCDTIdWLANType);
TUint32 LanType = *field; //LanType should now have a value of 100

//Step4: Modify a value and store it back

*field = 30;

//[OR] field->SetL(30);

ptrTable->ModifyL(*dbSession);
delete ptrTable;
delete dbSession;