In this Product How-To article, Raima’s Jeff Parsons describes the procedures he went through to build a C++ interface for the company’s RDM Embedded 10.1 embedded DBMS.
I recently finished a project implementing a new C++ interface for the RDM Embedded 10.1 release. As a programmer that typically works on the internals of an embedded database engine it had been years since I had seriously worked with C++.
Having the chance to code in this language gave me an opportunity to discover how an elegant design can be implemented simply in a higher level language, a stark contrast from my previous experiences with C++.
The last major C++ project I worked on was Raima Object Manager (ROM) the original RDMe C++ interface. Working with ROM soured me a little on the practicality of using C++ in an embedded application. While ROM was powerful it was over engineered containing a dozen classes that had to be combined together in various ways to perform any database related operation.
Unfortunately it was often easier to use the low-level core API to accomplish something than it was to use the higher-level class libraries and the core API was always more efficient. To be fair ROM was designed during the infancy of C++ and object orientated programming so the original developers did not have 15 years of best practices to help them in their design decisions.
Early on we decided to avoid the pitfalls of ROM by keeping the new C++ interface clean and simple. In fact the interface contains only two base classes – the Db interface and the Cursor interface. These base classes contain methods common to all databases and records. The RDM ddlp tool is responsible for generating derived classes containing methods that are specific to a particular schema.
There is one Db class generated for each database definition and it derives from the base Db interface class. This class provides methods that allow the programmer to
* Open the database
* Create new records
* Obtain record scan cursors (collections ordered by location in a data file)
* Obtain key scan cursors (collections ordered by key value)
* Start read transactions
* Start write transactions
* Pre-commit transaction
* Commit transactions
* Abort transactions
* Start a read-only snap shot
There is one Cursor class generated for each record defined in a schema. These Cursor classes derive from the base Cursor interface class and provide methods that allow the programmer to
* Delete Records
* Disconnect Records from a set owner
* Connect Records to a set owner
* Reconnect Records to a new set owner
* Navigate through the records in the cursor
* Obtain record scan cursors (collections ordered by file location)
* Obtain key scan cursors (collections order by key value)
* Obtain a cursor containing member records (collections related by set owner)
* Obtain a singleton cursor containing an owner record
* Update individual field values
* Update all field values
* Read individual field values
* Read all field values
* Find records by a key value