I’m working on some server/client based application at the moment.
The application is multi-threaded, has plugin-support (via dlopen,…) and should work with multiple databases.
Now I’m looking for some hints to start the design of the DBI-ABC. First, I thought about a simple Interface like this:
typedef struct {
unsigned int userid;
std::string username;
std::string fullname;
unsigned int usermodes;
} user_row_t;
class AbstractDBI
{
public:
virtual ~AbstractDBI() {};
virtual bool getUserData(int userid,user_row_t &row) const = 0;
virtual bool setUserData(user_row_t &row) const = 0;
// ...
}
This design is enough to handle all statements, used by the application core. But if we need database access in user written plugins, we would have to touch the DBI classes.
As the application will be under heavy load, prepared statements are something essential. Also we want to use database specific data-types, for example inet for postgres.
Has anyone done something like this and could give me some advice?
Ive never designed something like this myself, but one example I have seen used before is a setup where database records were stored in a structure that was essentially a
std::map<std::string, boost::any>, only the types described themselves, so you knew what they were, unlikeboost::any. SQL queries could then be run against the DB, and you’d get one of these generic structures back with the fields you asked for.If you put this stuff into a base class, then you can derive concrete classes that handle the DB specific details – this should let you swap DB’s whenever you like, and provide full flexibility to your plugins.
Although, if you dont want to allow full freedom to the plugins, I suppose you could give them access on a restricted user.