A database engine has exactly one non-negotiable job: never silently corrupt what it was trusted to store — and until this release, one interior b-tree rebalance path inside OxiSQL’s own SQLite engine could do precisely that.
On July 17 we released OxiSQL 0.3.3 — a release that makes SQLite views first-class, lets a compound SELECT act as a FROM-clause subquery or CTE, opens a database straight from an in-memory byte buffer, adds PostgreSQL logical replication, and fixes a b-tree index-page corruption bug reachable on real, index-heavy workloads.
No C. No Fortran. No libpq, no libmysqlclient, no libsqlite3, no zstd-sys — OxiSQL’s dependency graph is exactly as C-free in 0.3.3 as it was the day the oxisqlite fork replaced the last C SQLite binding. This release adds a large slice of SQL surface and closes real correctness bugs without adding a single native dependency to do either. It compiles to a single static binary and runs everywhere Rust runs — including, as of 0.3.3’s new open_from_bytes, places that never touch a writable filesystem at all.
Why OxiSQL 0.3.3 is a game changer
Every one of these was a real, load-bearing gap — not a nice-to-have:
- Referencing a
VIEWwasn’t just unsupported SQL — views did not exist as schema objects at all;type='view'rows insqlite_schemawere dead weight. - A compound
SELECT(UNION/INTERSECT/EXCEPT) could not appear as aFROM-clause subquery, a CTE, or a view body — rejected outright with “Only non-compound SELECT queries are currently supported.” - Loading a SQLite database meant a filesystem path, full stop — no way to open one directly from a byte buffer for a WASI, browser, or read-only-filesystem target.
- PostgreSQL support covered OLTP query/transaction plumbing but had no CDC story — nothing for a downstream consumer that needs a change stream instead of a poll loop.
- Worst of all: inserting into an index-heavy table could, under a specific and real page-rebalance shape, panic in a debug build — and silently corrupt the page in a release build.
OxiSQL 0.3.3 ends all of that:
- Views are first-class.
CREATE VIEW/DROP VIEW, querying views inFROM(including views-of-views and multi-wayLEFT JOINs), validated end-to-end against a real 9.5 MB PROJ database — 7 views over 40 tables, 21 indexes, and 37INSTEAD OFtriggers, everycount(*)and content query matchingsqlite3byte-for-byte. - Compound
SELECTnow works as a subquery, CTE, or view body, driven through the same coroutine machinery as a plain subquery. open_from_bytesopens a database straight from a byte slice — no temp file, mirrors SQLite’ssqlite3_deserialize(), and unlocks WASI/browser/read-only-filesystem deployments.- PostgreSQL logical replication — a full CDC path via
PgReplicationConnection, completepgoutputwire-protocol decoding, LSN tracking, andCOPY BOTHstreaming with keepalive. - The b-tree index-page corruption bug is fixed.
insert_into_cellnow only takes the in-place path when the target position is provably within the page’s physical cell array. - A second, independent durability bug is fixed alongside it.
commit_tx()now persists to the WAL before marking a transaction visible, closing a crash-window data-loss gap, and 40+ page-access call sites were hardened against aliasing violations caught by Miri.
Technical Deep Dive: where 0.3.3’s SQL surface and its correctness fixes actually live
- The facade and drivers (
oxisql,oxisql-core,oxisql-parse,oxisql-embedded,oxisql-postgres,oxisql-mysql,oxisql-sqlite-compat,oxisql-datafusion,oxisql-pool,oxisql-migrate). Oneoxisql::connect(uri)dispatches by URI scheme; theConnection/Transaction/Valuetraits inoxisql-coreunify every backend behind one async API, including the defaultexecute_named/query_namedmethods every backend inherits for free. oxisqlite-core, the storage engine, is where essentially all of 0.3.3’s SQL-surface growth and correctness fixes live: the view catalog andFROM-clause expansion, the compound-SELECT-as-subquery coroutine path, thetranslate/planner (CTAS,EXCEPT/INTERSECT,ON CONFLICTclauses), the B-tree/pager/WAL layer (the corruption fix, the MVCC durability fix, the WAL-checkpoint bookkeeping fix), and the VDBE executor (REGEXP, the newprintf()specifiers).oxisql-postgrescarries the new opt-inreplicationfeature. Becausetokio-postgresitself cannot negotiate replication mode,PgReplicationConnectiondrives the wire protocol directly through a newpostgres-protocoldependency — fullpgoutputdecoding,COPY BOTHstreaming via a background reader task plus a periodic Standby Status Update keepalive, and a brace/quote/escape-aware decoder for PostgreSQL’s{...}array-literal text format.- The patch-shim layer (
whoami-patched,zstd-shim,rustls-rustcrypto-patched, applied via[patch.crates-io]) keeps the whole--all-featuresworkspace — DataFusion’s Arrow IPC path included — free ofobjc2-system-configuration,zstd-sys, and the CRL-parsing CVE, untouched by anything in this release.
Getting Started
cargo add oxisql --features sqlite,pool-sqlite-compat
Views are the headline addition — they work the way you’d expect inside the C-free oxisqlite engine:
use oxisql::SqliteConnection;
use oxisql::prelude::*;
#[tokio::main]
async fn main() -> Result<(), oxisql::OxiSqlError> {
let conn = SqliteConnection::open_memory().await?;
conn.execute("CREATE TABLE users (id INTEGER, name TEXT, active INTEGER)", &[]).await?;
conn.execute("INSERT INTO users VALUES (1, 'Alice', 1), (2, 'Bob', 0)", &[]).await?;
// CREATE VIEW / querying views is new in 0.3.3.
conn.execute(
"CREATE VIEW active_users AS SELECT id, name FROM users WHERE active = 1",
&[],
).await?;
let rows = conn.query("SELECT name FROM active_users ORDER BY name", &[]).await?;
for row in &rows {
println!("{:?}", row); // → Alice
}
Ok(())
}
And 0.3.3’s other new entry point — opening a database directly from bytes, no filesystem required:
use oxisql::SqliteConnection;
#[tokio::main]
async fn main() -> Result<(), oxisql::OxiSqlError> {
let image: &[u8] = include_bytes!("bundled.sqlite");
let conn = SqliteConnection::open_from_bytes(image).await?;
let rows = conn.query("SELECT count(*) FROM sqlite_master", &[]).await?;
println!("{:?}", rows);
Ok(())
}
What’s New in 0.3.3
- Views:
CREATE VIEW [IF NOT EXISTS]/DROP VIEW [IF EXISTS], view-catalog loading, and querying views inFROM(aliases, joins, aggregates,UNION ALLbodies, views-of-views with cycle detection) — SQLite-matching diagnostics throughout, validated against a real 9.5 MB PROJ database. - Compound
SELECTas subquery/CTE/view body:UNION/UNION ALL/INTERSECT/EXCEPTcan now appear insideFROM (...), aWITHCTE, or a view definition. open_from_bytes: open a SQLite database from a byte buffer with no temp file, acrossoxisqlite-core,oxisqlite, and theoxisql-sqlite-compatfacade (async, and sync behind theblockingfeature).- PostgreSQL logical replication (
postgres-replicationfeature):PgReplicationConnection+ReplicationStreamfor CDC-style streaming, fullpgoutputdecoding, LSN tracking,COPY BOTH. - SQL surface growth:
ON CONFLICTclauses onCREATE TABLEconstraints,CREATE TABLE ... AS SELECT,EXCEPT/INTERSECT,OFFSET/ORDER BY/WITHon compoundSELECT, parenthesized join sources, virtual-tableORDER BYpushdown, theREGEXPoperator, and five moreprintf()specifiers. - Named parameters in the raw
oxisqliteengine::name/@name/$name/#namenow bind correctly instead of panicking. - Windows file locking, real
server_version()accessors onPgConnection/MyConnection, and a cleaner REPL error renderer. - Fixed — correctness:
UPDATE ... RETURNINGreturning zero rows,ALTER TABLE ... RENAMEcrashing on any schema with a view/trigger/vtab anywhere in it, multi-rowINSERTinto virtual tables keeping only the last row,IN (...)as a value expression, CTEs referenced more than once, wide-row (127+ column) record encoding,BLOB/TEXTcoercion inQUOTE()/||/concat(),strftime()%Jand pad-override flags, and aPRAGMA auto_vacuum = FULLhigh-water-mark bug — all fixed. - Fixed — safety and durability: a b-tree index-page corruption bug reachable on real index-heavy workloads, an MVCC transaction-removal race, an MVCC commit-ordering durability gap, WAL checkpoint bookkeeping, a PostgreSQL connection-timeout hang, and Miri-driven memory-safety hardening across 40+ page-access call sites.
- Index-based access restored for
DELETE/UPDATEunder theindex_experimentalfeature — safe again now that the optimizer only keeps the plan when it proves the access path can’t corrupt the driving index mid-scan.
Tips
- Try views against a real schema, not just a toy one.
CREATE VIEW/DROP VIEWand view-of-view references are validated end-to-end against a 9.5 MB PROJ-style database in the test suite — if your schema has views, joins, andINSTEAD OFtriggers, 0.3.3 is the release that makes them queryable. open_from_bytesis the way to ship a read-only SQLite database into WASM or a browser. Pair it withinclude_bytes!for a bundled dataset, or withVACUUM INTO/sqlite3_serialize()output for a snapshot generated at runtime — no temp file, no writable filesystem required.REGEXPis unanchored by default, like SQLite’s own convention.'hello world' REGEXP 'wor'matches; anchor with^/$yourself for a full-string match:SELECT * FROM users WHERE name REGEXP '^A'.- Logical replication is opt-in and drives the wire protocol directly. Enable
postgres-replication(impliespostgres), thenPgReplicationConnection::connect(...),create_replication_slot(...), andstart_logical_replication(...)hand back aReplicationStream— call.ack(lsn)as you consume it to advance the slot. - If you were catching a panic out of the b-tree, MVCC, or corrupt-page paths, stop. Those sites now return typed errors (
LimboError::Corrupt,LimboError::InternalError) instead of aborting the process — replace panic-catching with normal error handling. - Two internal breaking changes, zero facade impact.
oxisqlite’sParams::Namedandoxisqlite-sqlite3-parser’s lexerTokentype both changed shape internally (Cow<'static, str>keys/tokens instead of ownedString/borrowed&'i [u8]). Nothing inoxisql’s public API — includingquery_named/execute_named— changed; only code that pattern-matches on those low-level engine types directly needs an update.
This is the foundation
OxiSQL’s facade/driver layer is 10 crates sitting on the 7-crate, C-free oxisqlite-* engine, alongside a perf benchmark crate and three vendored [patch.crates-io] shim crates (whoami-patched, zstd-shim, rustls-rustcrypto-patched) that exist solely to keep the --all-features build genuinely C-free. As of 0.3.3: 2,157 tests passing with default features, 2,651 with --all-features, 0 failing, 0 clippy warnings, across roughly 178,591 lines of Rust in 484 source files.
OxiSQL itself sits on OxiTLS (transport/TLS), oxicode (row serde), OxiCrypto (encryption-at-rest), and OxiStore (lower storage layer). It is depended on by oxirouter, oxirs, oxify, oxigdal-db-connectors, oximedia, oxigaf, and oxirag — the database tier each of those reaches for when it needs SQL.
Repository: https://github.com/cool-japan/oxisql
Star the repo if you want a SQL layer where “add views” doesn’t mean waiting for a rewrite, and a b-tree that never silently corrupts a page during a routine index rebalance.
The era of choosing between “a SQL engine with real SQL surface” and “a SQL engine without C” is over. Pure Rust SQL — sovereign, safe, and now correct on the paths that used to corrupt — is here.
— KitaSan at COOLJAPAN OÜ July 17, 2026