
On Behalf Of Corwin Joy
More thoughts after looking at the code: You use std::string for exception messages, names of fields, etc. I think this is a mistake. Many databases return internationalized wide error messages and use wide strings for table and column names. Also, you will ideally want your library to return internationalized error messages. In DTL we ended up converting halfway through to support this - much better to get it right in the first place.
That's a good point, though I'd rather make the whole system templated on the type of string that is used than force everyone to use a wide string type.
variant: I'm don't think the variant type will exactly fit what you want here. I like the discriminated union which I would consider to be a better choice than boost::any since row allocation efficiency is an
Boost.Variant is a discriminated union. It's a totally different beast than Boost.Any.
One major difference, though, is that you're going to want "sticky types".
I think this is more of an issue for a binding system. Boost.Database is more of simple uniform interface to a database. This type of functionality could be built on top of Boost.Database.
Also, I see that you are binding std::string as the type for character data in your variant type. Be aware that this leads you down the slippery slope of having to support arbitrary length strings with the associated problems that I mentioned in my previous post.
Arbitrary length strings are a common type in databases. I understand from your post that fixed length strings can be a problem, but I don't see why arbitrarily long ones are. My vision for this is to have a very simple interface than can easily be implemented on a wide range of databases and has just enough features to solve most problems. I'd say that in the vast majority of database projects the performance bottlenecks are going to be disk or network, even with a naïve database wrapper. I can see how there could also be room for a full ODBC implementation that gives users more fine grained control, but I think there will be a large group who just want something that's easy to use.
You're also going to want to bind a boost date_time type (maybe the ptime type), a wstring type, a blob type and possibly a long string type. Adding new types shouldn't be a big deal though so this could easily be skipped for the initial design. BUT, I think you will benefit from including a date type early on since this gives an early example of what I call "complex types", i.e. types that are held in your class but do not map directly to a primitive database type but instead require reading into some kind of intermediate buffer and then translation to give the final type.
2. Database data type and related information. You can't just assume
I agree. I'd probably add posix_time::time_duration, and gregorian::date too. If the database is going to be templatized anyway, it would be pretty easy to allow one of the parameters to be a type list with all of the types in the variant in it. this
from the C++ type. Sometimes you will need to specify extra information about the SQL type to bind nondefault values for use in things like mapping to larger strings, specifying non-default precision for dates etc. The database datatype will be driver layer specific, i.e. different for ODBC and various native driver layers.
If the user is using the non-C++ data type information, what they're doing won't be database-independent. I don't want to have to worry about what the underlying type is.
3. Mapping between 1 <--> 2. Can include things like the address of where to put the data, intermediate buffers that may be used to manage the mappings, possibly any conversion policy. Here is an example snippet from DTL where we ended up having all 3 of these things in a single class:
These are the types of things I'd prefer remain hidden. Aside from the complexity they add to the interface (I don't want to have to deal with buffers, I just want it to work!), it would be hard to make all this portable.