Library Proposal: Database access layer for C++

1,096 views
Skip to first unread message

Johann Anhofer

unread,
Jan 7, 2014, 4:24:31 AM1/7/14
to std-pr...@isocpp.org
Hello everyone, I'm going to submit a library proposal for adding a database access layer to the C++ standard.

The github repository for the sample implementation and the current draft of the proposal are located here:


Database access layer.pdf

Michał Dominiak

unread,
Jan 7, 2014, 6:26:35 AM1/7/14
to std-pr...@isocpp.org
> The driver_factory is a singleton class

Nope.

Andrew Tomazos

unread,
Jan 7, 2014, 7:26:45 AM1/7/14
to std-pr...@isocpp.org

Klaim - Joël Lamotte

unread,
Jan 7, 2014, 2:20:27 PM1/7/14
to std-pr...@isocpp.org
Very brief review:

 1. as already pointed, there is no reason at all to make driver_factory a singleton, in particular if it's just a tool to map informations, not something representing a part of the system on which the program executes. 

 2. If the purpose of driver_factory is to be a registry of avialable drivers where any module can add and remove drivers, then I would suggest:
      - renaming it to driver_registry (or driver_factory_registry)
      - use namespace functions instead of a (singleton or not) class
Something like:

    std::db::register_driver_factory( "sqlite", []{ return sqlite_driver::create(); }
    std::db::unregister_driver_factory( "sqlite" );
    auto drv = std::db::make_driver( "sqlite" ); // or create_driver("sqlite");

In which case some information about thread safety calling these functions would be ncessary.

Another way of doing this would be to make an accessor type:

    std::db::driver_registry_accessor db_registry;
    db_registry.register_driver_factory( "sqlite", []{ return sqlite_driver::create(); }
    db_registry.unregister_driver_factory( "sqlite" );
    auto drv = db_registry.make_driver( "squlite" );

In which case, there would be runtime information about when the registry (that is implementation defined) is modified,
these info being provided to the implementation by the constructor and destructor of the accessor type.
Just an idea.

The last way would be to let the driver implementation provide private types implementations with concrete classes declarations,
that would be used directly by the user. That way, no need to have a central registry, or at least not implemented through the standard.
As I'm not an expert in the domain, I'm just not sure why there would be a global driver registry that might not even be necessary in practice
in a lot of cases. 

3. does connection::key_value_pair is a suggestion or a detail to review later or do you mean it should be implemented as in this proposal?
4. it is not clear if connection is RAII type in this proposal, it is said that the connection is open() when open is called, closed when close() is called.
     If it was not intended, I would suggest to
     - add a constructors that take openning informations and does guarantee that the connection is open while the object is fully buill;
     - make the destructor call close() (or close the connection) if the connection is already open.
5. Why not provide a (set of) constructor taking a shared pointer to driver_interface instead of a name?
6. Why are driver_interface provided through raw pointers and not, for example, unique_ptr?
7. Could you add a section explaining what are DDL and DML statements?
8. The proposals says that it is supposed to provide an interface for any kind of database, which it seems to do until you reach the statement and result classes where it's specifically designed for SQL statements and query results. Could you clarify which is it: an interface for any kind of db or for sql based statements?
 It looks like it's not specialized for SQL.
9. The usage of std::string in the interface of private interfaces (result_interface for exemple) could be problematic:
   it prevent a C implementation. Not totally sure it's a problem but I think it's a wanted feature.
10. Why isn't a transaction acting like a transaction_scope? If transaction would be a RAII type, I think there would be no need for 2 types.
11. I think the value type should 
     - be defined in a way similar to boost::variant< std::sting, int, nullptr, value >, with implicit lexical casts to string.
     - have it's own separate proposal so that it can be used in several other kind of proposals, like a JSON library or a DOM library.
12. I'm not sure a special type is needed for parameter, or it would need to be a separate proposal too?

More later if I find the time

rb...@eudoxos.de

unread,
Jan 7, 2014, 3:00:53 PM1/7/14
to std-pr...@isocpp.org


On Tuesday, January 7, 2014 1:26:45 PM UTC+1, Andrew Tomazos wrote:

Sadly, it seems to be pretty dead. I applied for membership about two months ago, still pending. I also tried to get in touch with Bill Seymour, but no luck yet.

Aleksandar Fabijanic

unread,
Jan 7, 2014, 3:30:59 PM1/7/14
to std-pr...@isocpp.org
On Tue, Jan 7, 2014 at 2:00 PM, <rb...@eudoxos.de> wrote:

> Sadly, it seems to be pretty dead. I applied for membership about two months
> ago, still pending. I also tried to get in touch with Bill Seymour, but no
> luck yet.

I think Bill Seymour stepped down and Mike Spertus is heading the SG now.

Otherwise, I'm somewhat unsure that SQL library should be called
"Database Library". Today, the term "database" covers a technological
space much broader than SQL databases.

Alex

>
> --
>
> ---
> You received this message because you are subscribed to the Google Groups
> "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to std-proposal...@isocpp.org.
> To post to this group, send email to std-pr...@isocpp.org.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/.

rb...@eudoxos.de

unread,
Jan 7, 2014, 3:50:07 PM1/7/14
to std-pr...@isocpp.org


On Tuesday, January 7, 2014 10:24:31 AM UTC+1, Johann Anhofer wrote:
Hi,

It is refreshing to see that there is action in the database realm :-)
I also became aware of a few things by reading the PDF, examples and the todo list, for instance that chunked retrieval of blobs might be a requirement.

As Joel has mentioned, it is a bit unclear, whether your library aims to support all kinds of databases or targets SQL specifically. In the latter case, I admit that I am not too fond of the text-based approach. This is probably not a big surprise if you look at https://github.com/rbock/sqlpp11 , where I present my EDSL approach (which might result in a proposal one day, too). Personally I prefer the EDSL approach because

  • it enables the compiler to check names of tables, columns, commands against typos
  • it enables the compiler to check if you are comparing apples and oranges (type safety)
  • it could even enable the compiler to make some semantical checks, e.g. if your FROM clause contains all tables required by the rest of the query
  • it allows the library to determine the names and types of result columns at compile time so that you get the same level of checks for results as for queries
  • it creates a syntax tree that can be translated into a string, but it could also be evaluated in different ways, which (I think) would make it much easier to create something similar to LINQ, which works on containers and streams, too
  • this also enables the library to handle subtle differences between databases without the help of the programmer, for instance decide whether to use the concat operator or a concat function.

I don't know why, but most C++ SQL library interfaces throw all the cool things of C++ overboard. Instead they resort to text based approaches relying on the user to get it right with intense code staring and a bunch of casts or similar operations. Libraries in other languages are much more advanced here, for instance python (http://www.sqlalchemy.org/) or .NET (LINQ).

Regards,

Roland

rb...@eudoxos.de

unread,
Jan 7, 2014, 3:51:50 PM1/7/14
to std-pr...@isocpp.org
On Tuesday, January 7, 2014 9:30:59 PM UTC+1, aleks.fabijanic wrote:
On Tue, Jan 7, 2014 at 2:00 PM,  <rb...@eudoxos.de> wrote:

> Sadly, it seems to be pretty dead. I applied for membership about two months
> ago, still pending. I also tried to get in touch with Bill Seymour, but no
> luck yet.

I think Bill Seymour stepped down and Mike Spertus is heading the SG now.

Huh, I missed that. Thanks for the info!

Roland

Michael Spertus

unread,
Jan 7, 2014, 8:55:45 PM1/7/14
to Aleksandar Fabijanic, std-pr...@isocpp.org
I don't believe I am heading the SG, but I hope to liven it up with a proposal for Issaquah.

Mike

Sent from my iPhone

Johann Anhofer

unread,
Jan 8, 2014, 3:01:20 AM1/8/14
to std-pr...@isocpp.org
Hi!

First of all, as Joel and Aleks also pointed out, my proposal always was meant for "SQL based Relational Database Systems", I will fix this in the PDF. 

sqlpp11 looks like a very cool thing, but it is one step higher on the abstraction hierarchy than my library.
It is meant to be a solid base for interactions with sql based relational database systems, e. g. to serve
as base for implementations like yours, because finally if your library want to transfer data from and to the database,
you will need to assemble a SQL command and execute it against the database.

The reason for the string based approaches are easy to state: SQL is a very, very complex and big language, with a huge number of different dialects, even between different versions of the same database system. 

I'm looking forward to see a proposal from you.

Regards, Johann

Johann Anhofer

unread,
Jan 8, 2014, 3:35:24 AM1/8/14
to std-pr...@isocpp.org
Hi!

Thank you for the professional review:

ad 1) You're right, there is no need to nail down an implementation detail (singleton) in the proposal. I think the idea with the free functions (as you stated in 2.) are the most flexible.

ad 2) It was ment as thread safe registry. My first approach was to pass an instance of the private driver class to the connection constructor. 
  But there are a few drawbacks which lead me to the name based alternative:
  * Users must now about a private class of the implementation (which would be the only place)
  * Users can miss use the driver class (e.g. pass it to connection instances of different threads)
  * The lifetime of a driver is unclear to the user
 So with the name base approach the implementation is free to create instances of the driver class for each connection 
 or to use only one common instance. 
 
 The drawbacks of the named approach are:
  * Users can misspell driver names
  * a central registry is needed

ad 3) I'm not sure about this, may this should be discussed. The connection options are a key/value pair, sure strings will do it, but then may be a lot of conversions from/to strings are needed. 

ad 4) I'm not a big fan of doing long duration operations in a constructor, but it would be no problem to add such a constructor. The destructor already closes the connection (as state on page 6).

ad 5) see ad 2) 

ad 6) The raw pointers approach was done for greater flexibility of the implementers. But sure unique_ptr's would be much better.

ad 7) DDL are Data Definition Language (like create/drop table/view/procedure), DML are Data Manipulation Language (insert, update, delete).
        I will add footnotes in the PDF for that. 

ad 8) This was my fault: The library is intended to be used for SQL based relational database systems. I think for e.g. NoSQL Databases are so different that they should handled with a separate library.

ad 9) There are other C++ features used in the interfaces (shared_ptr, classes) which prevents a C implementation. So I think in case of a C implementation there should be a C++ layer above of the C functions which implements the interface.

ad 10) The transaction object is for finer control to say explicit start here/end here. The destructor rolls the transaction back if the programmer has forgotten to commit the transaction, which in my opinion is always better than an implicit commit.
On the other hand if one uses the scope class he is aware of the implicit commit on scope exit.
It's like the mutex/lock_guard. A lock/transaction should be carefully used.

ad 11) I'm not sure about the first point? Is this meant as recursive definition ?
 But you're absolutely right that a separate proposal for this type is needed.

ad 12) The parameter class is a value class including an index (string or int), so I think there is a need for a separate class, but no need for a separate proposal.

Regards, Johann

Roland Bock

unread,
Jan 8, 2014, 3:48:47 AM1/8/14
to std-pr...@isocpp.org
On 2014-01-08 09:01, Johann Anhofer wrote:
>
> sqlpp11 looks like a very cool thing, but it is one step higher on the
> abstraction hierarchy than my library.
> It is meant to be a solid base for interactions with sql based
> relational database systems, e. g. to serve
> as base for implementations like yours, because finally if your
> library want to transfer data from and to the database,
> you will need to assemble a SQL command and execute it against the
> database.
Sure, sqlpp11 requires a connector, basically something at level 2 of
your proposal, which is closely related to a specific database or a meta
connector which can handle several databases (similar to your level 1).

But the connector does not necessarily require a string. And an
expression tree contains the structure of the query which makes it easy
to transform it into other representations (easier than parsing a
string, IMHO).
>
> The reason for the string based approaches are easy to state: SQL is a
> very, very complex and big language, with a huge number of different
> dialects, even between different versions of the same database system.
I'd argue that due to the complexity of SQL and the differences in
support for certain aspects of the language, we should give the
programmer every bit of help the compiler could offer. And ONLY if the
programmer wants to use a vendor specific feature that is not directly
supported by the SQL library, he should use strings as a fall-back (in
sqlpp11, that's what the verbatim method is for).

That does not mean that I consider string based approaches useless, but
I think they should not be the primary interface.
>
> I'm looking forward to see a proposal from you.

That will certainly take a few months :-)
I currently finishing support for prepared statements and some other
requests from the boost mailing list. And I want to think about querying
containers for some time before proceeding (this is where query
structures are certainly going to be useful).


Regards from Munich,

Roland

Csaba Csoma

unread,
Jan 8, 2014, 12:24:26 PM1/8/14
to std-pr...@isocpp.org
CppDB is a small library and it can be used independently.
Dual-licensed Boost and MIT.

It has connection pool and query-precompile.
We're using it with Postgres and Oracle; it is the fastest and best implementation I could find.

With Soci my app was serving 1,500 requests/sec.
Just switching it out for CppDB it went up to 8,500 requests/sec - same laptop, nothing else changed.


Csaba

Klaim - Joël Lamotte

unread,
Jan 8, 2014, 2:39:42 PM1/8/14
to std-pr...@isocpp.org
I think all these libraries have already been mentionned in a previous discussion on these forums.
However it seem that the proposal here is one of the only being made. 
It's good to know these libraries exists, but without any proposal been made, nothing can go forward.

Johann Anhofer

unread,
Jan 8, 2014, 3:30:50 PM1/8/14
to std-pr...@isocpp.org
This is exactly why I made the proposal, it serves as point to start with and it's not meant as, the one and only, best of all solutions.

Csaba Csoma

unread,
Jan 8, 2014, 4:23:01 PM1/8/14
to std-pr...@isocpp.org
My point was: can CppDB used as a reference implementation?

I saw Herb is proposing Cairo as a standard 2D library.
He said - and I agree with him - there's no reason to reinvent, if we already have a tested and working solution.

Csaba

Thiago Macieira

unread,
Jan 8, 2014, 4:47:33 PM1/8/14
to std-pr...@isocpp.org
On quarta-feira, 8 de janeiro de 2014 13:23:01, Csaba Csoma wrote:
> My point was: can CppDB used as a reference implementation?
>
> I saw Herb is proposing Cairo as a standard 2D library.
> He said - and I agree with him - there's no reason to reinvent, if we
> already have a tested and working solution.

Cairo is not C++ API. It can only be the backend and inspiration for the
graphics 2D API. It's much less controversial to propose a backend than to
propose an API.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358

Johann Anhofer

unread,
Jan 8, 2014, 5:32:05 PM1/8/14
to std-pr...@isocpp.org
Am Mittwoch, 8. Januar 2014 22:23:01 UTC+1 schrieb Csaba Csoma:
> My point was: can CppDB used as a reference implementation?

Of course it. can be used, but someone (the author of the library) has to write the paper!

Johann Anhofer

unread,
Jan 13, 2014, 10:22:32 AM1/13/14
to std-pr...@isocpp.org
A new version of the document is available. I've done some corrections and add-ons based on the reviews.
Database access layer.pdf

Roland Bock

unread,
Jan 13, 2014, 2:35:18 PM1/13/14
to std-pr...@isocpp.org
Hi,

it would be great if you could add a change history to the document. Otherwise its hard for others to figure out what changed.

Regards,

Roland

Johann Anhofer

unread,
Jan 14, 2014, 3:52:38 AM1/14/14
to std-pr...@isocpp.org
Hi! 

You are absolutely right, so here is the PDF with a change log.

Regards, Johann
Database access layer.pdf

Roland Bock

unread,
Jan 14, 2014, 4:51:51 AM1/14/14
to std-pr...@isocpp.org
Thanks :-)
--

Stack Machine

unread,
Jan 14, 2014, 6:34:49 AM1/14/14
to std-pr...@isocpp.org
Why do I need to know about SQL at all to use that? That doesn't make any sense to me.

Johann Anhofer

unread,
Jan 14, 2014, 6:39:34 AM1/14/14
to std-pr...@isocpp.org
It's not about using the classes in your code, it's about using SQL in your code. 
If you don't like SQL look for a SQL replacement Library (like Rolands).

David Krauss

unread,
Jan 14, 2014, 6:49:37 AM1/14/14
to std-pr...@isocpp.org
On 1/14/14 7:34 PM, Stack Machine wrote:
> Why do I need to know about SQL at all to use that? That doesn't make any
> sense to me.

I think this is a reason C++ shouldn't be trying to standardize a
generic database access layer: there is no universal query system to
build upon. SQL is but one attempt to create an interoperable database
interface, and the DBMS market is now moving away from interoperability
toward more specialized applications collectively called "noSQL."

If the proposal is really about SQL, then it should be clearly named as
such. It's probably better not to try to adapt SQL semantics to other
database systems, because while semantic approximations might fly in
some software ecosystems (which might even support impressive websites),
the C++ standard is all about unambiguous precision.

Roland Bock

unread,
Jan 14, 2014, 9:26:22 AM1/14/14
to std-pr...@isocpp.org
--
Hi,

I would not call sqlpp11 a SQL replacement library. It offers an EDSL to program SQL in C++ without writing strings. So instead of

"select alpha, beta, gamma from tab_sample where alpha > 7"

you have something like

select(tab.alpha, tab.beta, tab.gamma).from(tab).where(tab.alpha > 7);


This is obviously a bit more typing, but it comes with a lot of benefits, like the compiler checks for queries and results described earlier in this thread. It also allows the user of the library to write vendor-neutral SQL code. The vendor specific connector libraries then evaluate the expression tree in the "correct" way. For instance, postgres would concat three strings like a||b||c, mysql would use concat(a,b,c), oracle would do concat(a,concat(b,c)).

Thus, you would still need to know SQL to use the library, but
  1. the compiler would tell you about the mistakes you might make
  2. you don't have to care about vendor specific dialects of SQL


Whether it makes sense to try to use the SQL expression trees for other databases as well remains to be seen, but I guess it won't do so in all cases :-)

Regards,

Roland

PS: I plan to write a proposal for adding something like sqlpp11 to the standard, but this is certainly a few months from now.


Ville Voutilainen

unread,
Jan 14, 2014, 9:29:41 AM1/14/14
to std-pr...@isocpp.org
On 14 January 2014 16:26, Roland Bock <rb...@eudoxos.de> wrote:
> I would not call sqlpp11 a SQL replacement library. It offers an EDSL to
> program SQL in C++ without writing strings. So instead of
>
> "select alpha, beta, gamma from tab_sample where alpha > 7"
>
> you have something like
>
> select(tab.alpha, tab.beta, tab.gamma).from(tab).where(tab.alpha > 7);
>
>
> This is obviously a bit more typing, but it comes with a lot of benefits,
> like the compiler checks for queries and results described earlier in this
> thread. It also allows the user of the library to write vendor-neutral SQL
> code. The vendor specific connector libraries then evaluate the expression
> tree in the "correct" way. For instance, postgres would concat three strings

And, in theory, _in theory_, it may be mappable to non-sql databases.
Having said that, we should keep in mind that for advanced users who
need access to every advanced feature and need maximal performance,
being able to use raw queries is paramount, and existing almost-vendor-neutral
solutions more of less fail at achieving these goals unless they allow
for using raw queries when necessary.

Roland Bock

unread,
Jan 14, 2014, 9:54:27 AM1/14/14
to std-pr...@isocpp.org
On 2014-01-14 15:29, Ville Voutilainen wrote:
> On 14 January 2014 16:26, Roland Bock <rb...@eudoxos.de> wrote:
>> I would not call sqlpp11 a SQL replacement library. It offers an EDSL to
>> program SQL in C++ without writing strings. So instead of
>>
>> "select alpha, beta, gamma from tab_sample where alpha > 7"
>>
>> you have something like
>>
>> select(tab.alpha, tab.beta, tab.gamma).from(tab).where(tab.alpha > 7);
>>
>>
>> This is obviously a bit more typing, but it comes with a lot of benefits,
>> like the compiler checks for queries and results described earlier in this
>> thread. It also allows the user of the library to write vendor-neutral SQL
>> code. The vendor specific connector libraries then evaluate the expression
>> tree in the "correct" way. For instance, postgres would concat three strings
> And, in theory, _in theory_, it may be mappable to non-sql databases.
Yes, but it remains to be seen whether that really makes sense.
Personally, I would like to try to apply it to XML data and standard
container. But that is not more than a vague idea.

If you would like to experiment with something like that, I'd ask you to
wait another two weeks (or, if you are feeling adventurous, to look at
the "vendor_neutrality" branch,
https://github.com/rbock/sqlpp11/tree/feature/vendor_neutrality).
> Having said that, we should keep in mind that for advanced users who
> need access to every advanced feature and need maximal performance,
> being able to use raw queries is paramount, and existing almost-vendor-neutral
> solutions more of less fail at achieving these goals unless they allow
> for using raw queries when necessary.
>
sqlpp11 offers a function verbatim() which allows you to enter a strings
for things that are not covered by the EDSL. For example

auto special_feature = sqlpp::verbatim<sqlpp::boolean>("....");

select(tab.alpha, tab.beta, tab.gamma).from(tab).where(tab.alpha > 7 and special_feature);


Regards,

Roland

xavi

unread,
Jan 14, 2014, 2:40:49 PM1/14/14
to std-proposals
I find the proposal interesting, and though I agree with someone who commented that a non-string-based interface would be interesting, it can be implemented on top of this, and it's good to start somewhere.

I have a specific concern about transaction_scope. I find transactions being automatically committed if an exception is raised deeply disturbing. It has nothing to do with unlocking a mutex, which should happen both for normal returns and exceptions. Transactions should be explicitly committed, so the semantics of transaction are just fine, there is no need for transaction_scope, which I find dangerous.


2014/1/14 Roland Bock <rb...@eudoxos.de>

Csaba Csoma

unread,
Jan 15, 2014, 5:44:07 PM1/15/14
to std-pr...@isocpp.org
 > Why do I need to know about SQL at all to use that? 

It was tried and it does not work. Most of the (other) languages have at least several ORMs and they all fail when the app grows.

There's no known abstraction yet that would work. Especially when you start using a JOIN the ORM will generate hundreds of queries that kills your DB when you scale.

So people fall back to un-secure hand rolled SQL code, cache with invalidation issues and other "tricks" to get around the problem.


> I think this is a reason C++ shouldn't be trying to standardize a 
> generic database access layer.

I agree.
This should be done on a library level, something small and fast like CppDB.

But I think it is not possible to create a generic C++ SQL library without introspection or some special compiling step (like Protocol Buffers).
So unfortunately my guess is that compiler support will be needed to make it type safe and generator-free.


 the DBMS market is now moving away from interoperability 
> toward more specialized applications collectively called "noSQL." 

No, it does not.
If anything the market (Silicon Valley?) is moving back to SQL after trying to use key-value stores for everything, most of which did not work.





> you have something like
> select(tab.alpha, tab.beta, tab.gamma).from(tab).where(tab.alpha > 7);

That would be a great syntax! Type safe and SQL injection attack safe.
No string concatenation anywhere.


> sqlpp11 offers a function verbatim() which allows you to enter a strings 
> for things that are not covered by the EDSL.

I would suggest calling it "unsafe_sql()" instead of "verbatim()".

Csaba



Roland Bock

unread,
Jan 16, 2014, 3:07:34 AM1/16/14
to std-pr...@isocpp.org
On 2014-01-15 23:44, Csaba Csoma wrote:
 
> I think this is a reason C++ shouldn't be trying to standardize a 
> generic database access layer.

I agree.
This should be done on a library level, something small and fast like CppDB.
For direct interaction with the database? I agree.


But I think it is not possible to create a generic C++ SQL library without introspection or some special compiling step (like Protocol Buffers).
So unfortunately my guess is that compiler support will be needed to make it type safe and generator-free.
sqlpp11 is aiming to offer a generic type-safe SQL frontend. It creates an expression tree of your queries and then lets vendor-specific libraries evaluate this tree for interaction with the actual database. Vendor-specific optimizations could very well be done during the evaluation step.

The vendor-specific-evalution of a tree is currently under development, I guess it is gong to be released by the end of this month.


> you have something like
> select(tab.alpha, tab.beta, tab.gamma).from(tab).where(tab.alpha > 7);

That would be a great syntax! Type safe and SQL injection attack safe.
No string concatenation anywhere.
Thanks :-)

That is available today in sqlpp11. And the same type safety is given for results, btw.

We have been using this and a forerunner version for several years on our company and it really is a game changer.  The compiler basically finds all the stupid mistakes before they could ever hit even the unit tests. We can therefore concentrate on the business logic.

The only real requirement for using sqlpp11 in code like shown above is that you have to know your tables and columns at compile time and tell your compiler about them by introducing classes that represent these tables and columns. You might want to use a code generator to create this class representations for the tables you have (but it is not necessary).

If for some obscure reason you do not know your tables at compile time, then sqlpp11 could still help a lot with preventing code injection or making stupid mistakes in the query syntax, but the benefits would certainly be less dramatic.


> sqlpp11 offers a function verbatim() which allows you to enter a strings 
> for things that are not covered by the EDSL.

I would suggest calling it "unsafe_sql()" instead of "verbatim()".

Thanks for the suggestion. In the spirit of the library that's probably a better name, indeed :-)


Johann Anhofer

unread,
Jan 16, 2014, 4:25:00 AM1/16/14
to std-pr...@isocpp.org
Your are right! 

A transaction shouldn't be committed in an exceptional case. 

It's possible to rollback the transaction in case of an exception, using std::uncaught_exception:

~transaction_scope()
{
  if (std::uncaught_exception())
    _transaction->rollback();
  else
    _transaction->commit();
}

would be this ok, or should I remove the class completely?

Thanks, Johann

Johann Anhofer

unread,
Jan 17, 2014, 9:03:43 AM1/17/14
to std-pr...@isocpp.org
If added the changes of transaction_scope now to the document and renamed the document, as requested, to "Relational Database Access Layer".

Johann
Relational Database access layer.pdf

Johann Anhofer

unread,
Jan 26, 2014, 5:12:37 PM1/26/14
to std-pr...@isocpp.org
Is there anyone, who can present my proposal (N3886) at the Issaquah meeting?
It's not possible for me to do it myself.

Johann

Diggory Blake

unread,
May 31, 2014, 8:26:04 PM5/31/14
to std-pr...@isocpp.org
I think it's a bad idea to use "std::uncaught_exception()". What you really want is to detect if a new exception has been thrown (and not caught) since the construction of the transaction_scope, and I have no idea if that's even possible, especially when you consider that it might be heap allocated, or its lifetime explicitly controlled.

See what happens if transaction_scope is used from a destructor which is itself called during stack unwinding:

class C {
public:
   
~C() {
        transaction tr
{conn};
       
{
            transaction_scope trs
{&tr};
           
// ... modify database. For example, by logging that an instance of "C" was destructed ...
       
}
   
}
};

void test() {
    C c
;
   
throw "Oops!";
   
// ~C() called, but transaction is rolled back even though no exception was thrown during the transaction!
}

Better explanation:
http://www.gotw.ca/gotw/047.htm

David Krauss

unread,
May 31, 2014, 11:40:59 PM5/31/14
to std-pr...@isocpp.org

On 2014–06–01, at 8:26 AM, Diggory Blake <dig...@googlemail.com> wrote:

> I think it's a bad idea to use "std::uncaught_exception()". What you really want is to detect if a new exception has been thrown (and not caught) since the construction of the transaction_scope, and I have no idea if that's even possible, especially when you consider that it might be heap allocated, or its lifetime explicitly controlled.

It’s possible, but requires some data structures. See my std-proposals thread "Transaction lifetime oriented replacement for uncaught_exception” from September 2013.

If someone wants to pursue this research avenue, it would be nice to have a collaborator.

Johann Anhofer

unread,
Jun 1, 2014, 4:03:17 PM6/1/14
to std-pr...@isocpp.org
It seems to be a problematic solution, so I think I should drop this little helper class transaction_scope.

On the other hand, I would avoid code that executes SQL statements in a destructor, this leads all to easy to bad behavior, which is hard to track down.

Your example also lacks the exception handler which is an absolutely must in a destructor, but the problem remains, right?

Johann

Diggory Blake

unread,
Jun 1, 2014, 5:01:02 PM6/1/14
to std-pr...@isocpp.org
Yeah, it can always be added in later when these problems with RAII are properly resolved.

I don't think there's any reason why you shouldn't execute SQL in a destructor, as long as exceptions are properly handled. For example, with databases that support mutual exclusion, it might be essential to run an "unlock" command from the destructor the same way lock_guard works.

Yes, in my example I was ignoring the potential for the transaction itself to throw an exception, the problem still occurs even if transaction is noexcept.
Reply all
Reply to author
Forward
0 new messages