
Thanks for the red team corrections—this is exactly the kind of contribution that helps sharpen the review into something more useful to the reviewers. I’ll be revising the document with the following changes: 1. Type System Clarification - Add mention of STRICT tables introduced in SQLite 3.37, which enforce static typing. - Note that before STRICT, developers could enforce type constraints with CHECK(typeof(col)='type'). 2. Binding Persistence - Clarify that parameter bindings persist across executions of a prepared statement. - Update examples to reflect that some placeholders (like a parent FK) may be bound once and reused across multiple executions, with explicit reset if needed. 3. Transaction Semantics - Correct the statement “SQLite requires all operations to occur within transactions.” - Clarify that every standalone statement is its own implicit transaction if none is open. - In explicit transactions, each statement executes inside an implicit savepoint, which means a single failing statement doesn’t poison the whole transaction (contrasting PostgreSQL). 4. JSON Support - Reframe discussion of JSON. Acknowledge that SQLite has built-in JSON1 functions and operators (->, ->>), though it doesn’t expose a json type. - Position Boost.SQLite’s integration with Boost.JSON as an added ergonomic layer for C++ developers—helpful for working directly with boost::json::value, but not required to use JSON features. These edits will make the Problem Domain and Boost.SQLite Deep Dive sections both more accurate and better aligned with how practitioners actually use SQLite. On Tue, Sep 2, 2025 at 9:00 AM Dominique Devienne <ddevienne@gmail.com> wrote:
On Tue, Sep 2, 2025 at 2:36 PM Sergio DuBois via Boost <boost@lists.boost.org> wrote:
Type Mapping. SQLite's type system is dynamic: any column can store integers, text, or blobs at runtime.
Depends. There are STRICT tables. And before that, one could CHECK(typeof(col)='type') to emulate that.
Prepared Statements and Binding. SQLite encourages precompiled statements with parameter binding. In raw C this means multiple sqlite3_bind_* calls. Wrappers streamline this by accepting tuples, operator<< chaining, or lambda-based binding, making prepared statements both safe and ergonomic.
Regarding binding, many people don't realize binding is persistent. You don't need to bind all placeholders for every row/execution. I routine do that, inserting children of a given parent. The parent FK bind is common to all its children. Binds can be explicitly reset, and their lifetime is tied to the statement of course.
Transactions. SQLite requires all operations to occur within transactions. In C this means issuing BEGIN and ensuring COMMIT or ROLLBACK
False. Each statement is its own implicit transaction, if there isn't an explicit one. And when there's an explicit one, each statement is an implicit savepoint too, unlike PostgreSQL, where any statement error invalidates the whole transaction, the ROLLBACK is the one way to "recover" normal execution.
Modern Features. Some wrappers integrate JSON libraries
SQLite itself already contains two built-in APIs for text and binary (custom) json. The SQL grammar was also changed to support a json-specific operators ((-> and ->>)
But there are of course no json or jsonb data-types. These are APIs to manipulate text and blob values.
So there's no real need to integrate with external C++ JSON libraries. It's all text in and out (the jsonb "format" is internal, and not exposed publicly, even though it is documented).
That's the problem is AI, you can't really trust it :). --DD