
Dear Boost community, # Review of boost_sqlite First, I want to thank Klemens Morgenstern for his work on this library and proposing it to boost, and Mohammad Nejati for managing the review. I think a C++ sqlite3 wrapper is a tremendously useful library and given the widespread use of SQLite certainly a valuable addition to Boost.
- What is your evaluation of the design?
The library is a thin wrapper around sqlite3 adding C++ specific quality of life features such as RAII for resource management and a more idiomatic C++ interface around the bare C API. I particularly like: * Convenient parameter binding for statements * Boost Describe integration * Both throwing and non-throwing interfaces * Boost JSON integration (although I did not try that myself) However, I ran into a couple of issues with the design: * Owning vs view types: Some types are not clearly distinguished as owning or non-owning, which can lead to confusion and potential resource management issues. The `connection` and `resultset` types are two primary examples. This is particuarly troublesome since those types together with `statement` are at the core of interacting with SQLite. * `connection`: It has an explicit `take_ownership` parameter and the destructor (via unique_ptr) will maybe close the database. Instead, I would consider it much safer to have an owning `connection` and a non-owning `connection_ref` type. * `resultset`: The ownership problems with resultset and statement are quite obvious when looking at the contained unique_ptr deleter. It does completely different things depending on whether the resultset owns the underlying sqlite statement (finalize) or not (prepare for reuse). The problems associated with it are actually highlighted in the library documentation in a few places. I would encourage the author to rethink how the management of statements and the results that they produce. * Connection close behavior: The connection class `close` calls `sqlite_close` whereas the destructor (via the unique_ptr deleter) calls `sqlite3_close_v2`. Despite the similarity in name, those two functions behave quite differently if there are outstanding database resources or operations such as prepared statements: `sqlite3_close` will fail with `SQLITE_BUSY` if there are any outstanding resources, whereas `sqlite3_close_v2` will forcibly release all resources. This difference came at a bit of surprise to me since it is not spelled out in the reference that close might not actually close. * Transaction scoping rules: The scoping rules around transations, statements and resultset are suprising. The following example demonstrates that: ``` { sqlite::transaction t{conn}; // use a transaction to speed this up auto st1 = conn.prepare(R"(insert into libitems (length, content_type) values ($length, $content_type) returning id)"); auto st2 = conn.prepare(R"(insert into libpaths (path, libitem) values ($path, $libitem))"); //{ // uncomment this scope to make it work auto res = st1.execute<rowid>({{"length", 123}, {"content_type", "application/octet-stream"}}); rowid id = res.current(); st2.execute({{"path", "lib/path/to/file"}, {"libitem", id.id}}); //} t.commit(); } ``` The requirement of this extra scope around the resultset was quite surprising to me. Nowhere in the library documentation is this behavior explained. I would much rather prefer the scope of the transaction itself sort out the order of destruction to make sure it commits correctly without extra nested scopes. If that's not possible, at least the library documentation needs to make the user aware of those subtleties. * Use of cstring_ref instead of string_view for text field and values: This is flawed in my opinion. sqlite3 recommends to access TEXT fields using `sqlite3_column_text` followed by `sqlite3_column_bytes` to get the length. This indicates that the text column could very well contain NUL bytes (despite causing problems in expressions) making a C-style string the wrong choice. * Completeness: Quite a few functions acting on the `statement` type are missing and the statement type also does not expose its underlying handle.
- What is your evaluation of the documentation?
Insufficient. The introduction and introductory examples are reasonable. But the design and reference documentation is severely lacking. When trying to use the library, I eventually ended up not looking at the documentation any more. Instead, I read the source code to figure out the sqlite3 C API functions that are used and then read the sqlite3 C API documentation. Non-exhaustive list of documentation issues: * It mostly lacks precise documentation of pre and post conditions and invariants managed by the types. This is particulary bad for types that maybe or maybe not own resources like `connection` and `resultset`. * The invalidation rules are inadequately documented. For example, compare
The view types can be invalidated when the database changes or the next row is read by the query.
The field type does not own the statement/query it was produced by. It is a merely a view into the resultset. Reading the next row will change the values returned.
with https://sqlite.org/c3ref/column_blob.html I don't want to imply that the entire sqlite3 documentation needs to be copied, but the essential parts of how those invalidation rules apply to the C++ constructs should be stated. And a link to the relevant sqlite3 page would also be helpful. * Since it wraps the sqlite3 C API, it should clearly spell out and link to the sqlite3 types and functions that are used by the library. Just one example: `connection::close()` needs to specify that is calls `sqlite3_close` and not `sqlite3_close_v2` and/or repeat the corresponding sqlite3 documentation of its behavior, while `~connection()` should specify that it calls the latter. * There is not even a mention of conversion behavior for sqlite values. The reference documentation of value and field should at the very least make the user aware of potential conversions and link to the relevant sqlite3 documentation page that has the details of how conversions are done and when this might result in invalidation of previously returned string/blob references (if applicable). * The `transaction` documentation and examples should emphasize the scope requirements for statements and their results used within a transaction. For example, it seems that all resultset created during the transaction seem must be destroyed prior to calling `commit`. * I did not find any design documentation or rationale for the library's design decisions regarding ownership handling of sqlite3 resources. I have to read the implementation and guess the reasoning behind certain choices.
- What is your evaluation of the implementation?
I did only look at selected parts of the implementation whenever the docs were insufficient to explain the precise contracts of types and functions. What I saw was mostly what I would have expected from the thin wrapper around a C API. Random notes: * resultset: The destructor steps through the entire resultset rows. I don't think this is necessary since the sqlite3 docs would indicate that you can reset or finalize a statement at any time. * field access: Retrieving text fields should follow recommended sqlite3 practice: `sqlite3_column_text` followed by `sqlite3_column_bytes` to get the length. I also took a quick look at the tests. Those seem to be rather superficial. They don't cover much beyond the most basic usage scenarios for those types which I looked at.
- What is your evaluation of the potential usefulness of the library?
Potentially very useful. It does the tedious work of mapping the sqlite3 C API onto C++. I would use it if I need to work with sqlite from C++, but likely patched to avoid the ownership issues. Its usefulness is primarily limited by the lack of precise documentation which makes it very difficult to figure out the exact behavior of code that is written with the library.
Do you already use it in industry?
No.
- Did you try to use the library? With which compiler(s)? Did you have any problems?
Yes. I modified some of the examples to try out a few different queries and transaction related examples. I used debian 13 with its default gcc. Everything except the boost url dependent examples compiled.
- How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
A medium depth study from a user perspective. I spent a couple of hours on and off digging through the docs of the library (and the sqlite3 docs) and worked with the examples.
- Are you knowledgeable about the problem domain?
I'm proficient in C++ but have only had very limited exposure to the sqlite3 C API.
At the end of your review, please state clearly whether you ACCEPT, REJECT, or CONDITIONALLY ACCEPT (with explicit conditions) the proposed Boost.SQLite library.
Most of the issues raised in this review can be fixed. And most of it is "just" work. So I'm torn between conditionally accept and reject but encourage resubmission. The lack of documentation in particular precise reference documentation is the biggest issue in my opinion. It tips my recommendation towards REJECT but encourage resubmission. If the review manager decides to conditionally accept the library, I strongly recommend making significant documentation improvements the a condition for acceptance. Best regards Max On 8/25/25 06:52, Mohammad Nejati [ashtum] via Boost wrote:
Dear Boost community,
The review of Boost.SQLite by Klemens Morgenstern begins today, Monday, August 25, and runs through Wednesday, September 3, 2025.
Boost.SQLite provides a safer and more expressive C++ interface to the SQLite3 C-API to simplify usage and reduce errors.
You can read the documentation at: https://klemens.dev/sqlite and study or try out the code at: https://github.com/klemens-morgenstern/sqlite
This is the second review attempt. The first concluded without a result due to too few submitted reviews.
Anyone with experience in C++ or SQLite, at any level, is encouraged to contribute. In your review, please indicate how much time you spent on the evaluation.
Here are some questions you might find helpful when writing your review:
- What is your evaluation of the design? - What is your evaluation of the implementation? - What is your evaluation of the documentation? - What is your evaluation of the potential usefulness of the library? Do you already use it in industry? - Did you try to use the library? With which compiler(s)? Did you have any problems? - How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? - Are you knowledgeable about the problem domain?
At the end of your review, please state clearly whether you ACCEPT, REJECT, or CONDITIONALLY ACCEPT (with explicit conditions) the proposed Boost.SQLite library.
Your feedback is critical to the success of this review. Thank you in advance for your time, expertise, and contributions.
Best regards, Mohammad Nejati Review Manager for the proposed Boost.SQLite _______________________________________________ Boost mailing list -- boost@lists.boost.org To unsubscribe send an email to boost-leave@lists.boost.org https://lists.boost.org/mailman3/lists/boost.lists.boost.org/ Archived at: https://lists.boost.org/archives/list/boost@lists.boost.org/message/FK4NIN2J...