Creating and Modifying Database Objects in C++

C++ applications typically use a mix of C++ and C APIs to manage database objects. The mcocomp schema compiler with option -hpp generates C++ class definitions for each database class. These class interfaces can be used to create and modify database objects using these generated create() and _put() methods like the following:

 
    Schema snippet:
            
     
    class Part
    {
        string      type;
        string      name;
        float       price;
        unsigned<4> code;
         
        hash< code >        ByCode [ 10000 ];
        tree< type, name >  ByType; // ordered by type, name
    };
     
     
    Application snippet:
            
     
    MyPart part;
    char temp[200];
     
    rc = mco_trans_start(db, MCO_READ_WRITE, MCO_TRANS_FOREGROUND, &t);
    if ( MCO_S_OK == rc ) 
    {
        part.create(t);
        part.stype_put(i2s(j % 100));
        sprintf(temp, "part # %d", j);
        part.sname_put(temp);
        part.price_put((float)(2.0 + j % 100 / 200.0));
        part.code_put(1000000+j);
        rc = mco_trans_commit(t);
    }
     

But it may be preferable to take advantage of the smart pointer option described in the following section.

Optimizing C++ database access with the ''smartptr'' DDL compiler option

Sometimes it is possible and beneficial from a performance standpoint to access object fields in a С++ fashion as opposed to using the _put()and _get() functions. These setters and getters can be implemented in C++ by generating code that make database fields appear effectively as class “properties”.

For example, instead of:

 
    anObject.aField_get(&value));
    anObject.aField_put(1));
     

Using a smart pointer this can be written as:

 
    value = anObject.aField;
    anObject.aField = 1;
     

In order to use smart pointer access, simply specify the DDL compiler option -smartptr when compiling the schema with mcocomp to generate the C++ style access methods. It is possible (and may sometimes be necessary) for an application to combine the standard setters and getters with the smart pointers access method.

Apart from the intuitive C++ style and programming convenience of effectively treating database fields as class “properties”, another significant advantage is that exception handling can then be used to manage error conditions.

However, as the smart pointer implementation uses some “tricky” C++ features to simulate “properties” (implicit cast operators and constructors), in some cases this can lead to confusion for developers. While in most cases the developer need not be concerned about the internal implementation, in some uses there can be problems; for example when displaying a value using printf() or using the address of such a “property”.

And note that these “properties” extract values from the database using the eXtremeDB native API wrapper functions. While this can be efficient when accessing only those fields that are actually needed, it is not always the most efficient way of interacting with a database. For example, if all of the class fields need to be extracted then it is more efficient to extract them into a struct (see section “Fixed _put and _get” in the C API page) rather than access them field-by-field. Or if the application is accessing the same field multiple times, it is also preferable to “materialize” the field value (extract it into a local variable) rather than extract its value on each access via the “property” assignment.

For this reason the smart pointer option is provided, to enable or disable this feature. (It is disabled by default.) To illustrate the kind of internal implementation generated when the smart pointer option is specified, consider the following schema:

 
    class Host 
    {
        uint4 id;
        string name;
        char<50> domain;
    };
     

When mcocomp –hpp –smartptr schema.mco is executed, the following code will be generated for the integer field id:

 
    class Host : public MCO::Base_
    {
    public:
        struct 
        {
            Host* handle_;
 
            operator  uint4() const 
            {
                uint4 val_;
                MCO_CPP_CHECK(Host_id_get(handle_, &val_));
                return val_;
            }
 
            uint4 operator=(uint4 val_) 
            {
                MCO_CPP_CHECK(Host_id_put(handle_, val_));
                return val_;
            }
        } id;
        ...
    };
     

Dynamic Object Allocators

The eXtremeSQL engine manages dynamic data objects like Blob, String, Array etc. with an object of class Allocator. Please refer to the Dynamic Object Allocators page for further details.