1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
/*! \page backenddev Developing Your Own Backends
Even if your database is not supported directly by one of the backends, take a look on \ref odbc "ODBC" backend,
and see how well your database driver behaves with it. It may solve the problem for you.
Before you begin make sure you are familiar with CppDB library and know how to use it. Take a look to the
source code of existing backends, it is good to take a look on \ref postgresql "PostgreSQL" and \ref sqlite3 "Sqlite3" backends
implementations.
\section backenddev_what_needed What Need to Implement
You need to implement following 3 classes:
-# cppdb::backend::connection - the object that holds connection to the database - similar to cppdb::session.
-# cppdb::backend::statement - the object that holds prepared (or unprepared) statement - similar to cppdb::statement
-# cppdb::backend::result - the object that holds the result of query - similar to cppdb::result
You may safely assume that:
- As long as \ref cppdb::backend::result "result" exists, the \ref cppdb::backend::statement "statement" that created it would exist.
- As long as \ref cppdb::backend::statement "statement" exists, the \ref cppdb::backend::connection "connection" that created it would exist.
The frontend classes make sure that this happens.
\section backend_ref_dynamic Making Loadable Module
You need to implement a single entry point in your library with the \ref cppdb::backend::cppdb_backend_connect_function "following prototype".
It is very important to make the entry point function \c extern \c "C" so it would be resolved using dlsym or GetProcAddress functions
and it should be marked as "__declspec(dllexport)" if it is compiled as Windows DLL.
It should be named it as \c cppdb_xyz_get_connection where \c xyz is the name of your backend.
It should receive as a parameter a const reference to cppdb::connection_info returning newly created \ref cppdb::backend::connection "connection".
For example, in sqlite3 backend this function looks like this:
\code
extern "C" {
CPPDB_DRIVER_API cppdb::backend::connection *cppdb_sqlite3_get_connection(cppdb::connection_info const &cs)
{
return new cppdb::sqlite3_backend::connection(cs);
}
}
\endcode
The shared object or DLL themselves should be named as cppdb_xyz - so under Linux it would be libcppdb_xyz.so and under Windows MSVC it would
be "cppdb_xyz.dll". It is also good idea to give it same soname as the libcppdb.so itself as it would allow keeping several backend
versions for several versions of libcppdb in future as CppDB always tries to load a module as "libcppdb_xyz.so.V" and only
then "libcppdb_xyz.so" where V is the current CppDB library soname.
\section backend_ref_static Making Statically Linked only Module
Of course if you want to link your module statically only, you do not have to create this single entry point
function, you may derive from cppdb::backend::driver class such as its \ref cppdb::backend::driver::open() "open()" function
would return a new connection object and \ref cppdb::backend::driver::in_use() "in_use()" function would always return
true so the module would not be "unloaded".
Such module can be installed using \ref cppdb::driver_manager driver_manager singleton class using its \ref cppdb::driver_manager::install_driver() "install_driver()" member function. For example:
\code
class my_cool_sql_driver {
public:
cppdb::backend::connection *open(cppdb::connection_info const &ci) {
return new my_cool_sql::connection(ci);
}
bool in_use() { return true; }
};
...
cppdb::driver_manager::instance().install_driver("mycoolsql",new my_cool_sql_driver());
\endcode
Of course if you have the \c extern \c "C" function as shown above you can do the same trick using cppdb::backend::static_driver.
\code
extern "C" {
cppdb::backend::connection *my_cool_sql_open(cppdb::connection_info const &ci) {
return new my_cool_sql::connection(ci);
}
}
...
cppdb::driver_manager::instance().install_driver("mycoolsql",new cppdb::backend::static_driver(my_cool_sql_open));
\endcode
\section backend_tips Tips
- Use functions from utils.h and numeric_util.h they are very helpful especially in converting data to and from textual representation.
- When converting numbers to strings and backwards make sure you are using std::locale::classic(), otherwise when inserting
12345.678 you may accidentally get "12.345,678" which is probably not what you want. Do it as following:
\code
std::ostringstream ss;
ss.imbue(std::locale::classic());
ss << number;
std::string text_value = ss.str();
\endcode
And do the same for parsing.
- Try to reduce memory coping as much as possible when handing large texts and objects, remember that when std::string is binded
it remains valid till actual statement execution so it is likely that you can just keep a reference on it rather then
copying the string itself.
- Don't bother too much about statements caching or connection pooling. Front-end classes do this for you.
*/
|