We are going to introduce now the C++ binding through the same schema and examples as previously.
There are two ways to use the C++ binding:
We will explain here only the second way, as it is far more simple and pratical than the first one. For more information on the generic C++ binding, please refer to the C++ binding manual.
Writing a C++ program that can create, retrieve, modify and delete person instances that are stored in an EYEDB database involves the following steps:
This example is located in the examples/GettingStarted subdirectory.
To generate the specific C++ binding, run the eyedbodl tool as follow:
% eyedbodl --gencode=C++ --package=person schema.odlThe -package option is mandatory: you may give any name you want, this name will be used as the prefix for generated files names.
eyedbodl generates a few files, all prefixed by person, fhe most important being person.h and person.cc.
If you have a look to the file person.h, you will notice that the following classes have been generated:
The first class, person, is the package class:
class person {
public:
static void init();
static void release();
static eyedb::Status updateSchema(eyedb::Database *db);
static eyedb::Status updateSchema(eyedb::Schema *m);
};
it is used to perform package initialization and schema update.
Before any use of the person package, you need to call
person::init.
The second class, personDatabase is used to open, close and manipulate objects within a database containing the person schema.
The open method has two purposes: the first one is to open the database, as the standard eyedb::Database will do; the second one is to check that the database schema is consistant with the generated runtime schema. Although it is possible to use the standard Database class to open a database containing the person schema, it is strongly recommended to use the personDatabase class.
The third class, Root, is the root class for all the generated classes. This class is useful to perform safe down-casting during object loading.
The three last classes, Address, Person and Employee are generated from the person.odl class specifications: for each attribute in the person.odl, a set of get and set methods is generated.
For instance, for the firstname attribute, the following methods are generated:
eyedb::Status setFirstname(const std::string &); std::string getFirstname(eyedb::Bool *isnull = 0, eyedb::Status * = 0) const; eyedb::Status setFirstname(unsigned int a0, char); char getFirstname(unsigned int a0, eyedb::Bool *isnull = 0, eyedb::Status * = 0) const;The two first methods manipulate the firstname attribute as a string while the two last ones manipulate each character within this string.
There are two set methods and two get methods.
Here is the code for this minimal client:
#include "person.h"
int
main(int argc, char *argv[])
{
eyedb::init(argc, argv); // initializes EyeDB package
person::init(); // initializes person package
eyedb::Exception::setMode(eyedb::Exception::ExceptionMode); // use exception mode
try {
eyedb::Connection conn;
conn.open(); // opens the connection
personDatabase db(argv[1]); // creates a database handle
db.open(&conn, eyedb::Database::DBRW); // opens the database in read/write mode
}
catch(Exception &e) { // catch any exception and print it
e.print();
}
person::release(); // releases person package
eyedb::release(); // releases EyeDB package
return 0;
}
Note that statement Exception::setMode(...) is mandatory if you want to use the exception error policy.
To use this client, you must first compile it using a standard Makefile, as follows (replace «datadir» with the data directory, usually /usr/share):
include <<datadir>>/eyedb/Makefile.eyedb
CXXFLAGS += $(EYEDB_CXXFLAGS) $(EYEDB_CPPFLAGS)
LDFLAGS += ${EYEDB_LDFLAGS}
LDLIBS += ${EYEDB_LDLIBS}
all: persontest
persontest.o: person.h
person.o: person.cc
persontest: person.o persontest.o
$(CXX) $(LDFLAGS) -Wl,-R$(EYEDB_LIBDIR) -o $@ $^ $(LDLIBS)
person.cc person.h: schema.odl
$(EYEDB_ODL) --gencode=C++ --package=person $<
Important note: you need a recent version of GNU make to use this makefile. This makefile does not work with the standard SUN make.
Once compiled, you can execute the program as follows:
% ./persontest foo
We are going now to add a function to manipulate Person instances:
These operations are performed in the following function:
static void
create(eyedb::Database *db)
{
db->transactionBegin(); // starts a new transaction
Person *john = new Person(db);
john->setFirstname("john");
john->setLastname("wayne");
john->setAge(32);
john->getAddr()->setStreet("courcelles");
john->getAddr()->setTown("Paris");
Person *mary = new Person(db);
mary->setFirstname("mary");
mary->setLastname("poppins");
mary->setAge(30);
mary->getAddr()->setStreet("courcelles");
mary->getAddr()->setTown("Paris");
// mary them
john->setSpouse(mary);
// creates children
for (int i = 0; i < 5; i++)
{
std::string name = std::string("baby") + str_convert(i+1);
Person *child = new Person(db);
child->setFirstname(name.c_str());
child->setLastname(name.c_str());
child->setAge(1+i);
john->addToChildrenColl(child);
child->release(); // release the allocated pointer
}
// store john and all its related instances within the database
john->store(eyedb::FullRecurs);
// release the allocated pointers
mary->release();
john->release();
db->transactionCommit(); // commits the current transaction
}
A few remarks about this code:
We are now going to query and display all the person instances.
Here is the corresponding code:
static void
read(eyedb::Database *db, const char *s)
{
db->transactionBegin();
eyedb::OQL q(db, "select Person.lastname ~ \"%s\"", s);
eyedb::ObjectArray obj_arr;
q.execute(obj_arr);
for (int i = 0; i < obj_arr.getCount(); i++)
{
Person *p = Person_c(obj_arr[i]);
if (p)
printf("person = %s %s, age = %d\n", p->getFirstname(),
p->getLastname(), p->getAge());
}
db->transactionCommit();
}
An OQL construct can be used within the C++ code using the OQL(Database *, const char *fmt, ...) constructor. For instance, in the above example, assuming s is equal to baby, the code:
eyedb::OQL q(db, "select Person.lastname ~ \"%s\"", s);will send the query select Person.lastname "baby" to the OQL interpreter.
This interpreter will perform the query and returned all the found objects. The returned objects can be found using the OQL::execute method as follows:
eyedb::ObjectArray obj_arr; q.execute(obj_arr);
The returned objects are of type eyedb::Object, so you cannot use the Person methods such as getFirstname(), getAge()... To use them, you need to perform a down-cast using the Person_c static function as follows:
for (int i = 0; i < obj_arr.getCount(); i++)
{
Person *p = Person_c(obj_arr[i]);
if (p) ...
If the object obj_arr[i] is not of type Person, the returned
pointer will be null. It is why we make a test on the value of p.
If p is not null, we can use all the Person methods as follows:
printf("person = %s %s, age = %d\n", p->getFirstname(),
p->getLastname(), p->getAge());
To have more information about the C++ binding, please refer to the appriopriate manual.