oxisqlite-core
The engine core of the C-free oxisqlite engine — a Pure-Rust fork of limbo 0.0.22, internal to the OxiSQL workspace.
This is the heart of the engine that powers the oxisql-sqlite-compat backend.
It contains:
-
the VDBE bytecode interpreter,
-
B-tree storage, the pager, and WAL,
-
SQL → bytecode translation with a System-R cost-based optimizer,
-
ANALYZE statement +
sqlite_stat1cardinality statistics, -
MVCC transaction machinery (full
ROLLBACK,SAVEPOINT), -
UPSERT
ON CONFLICT DO UPDATE/DO NOTHINGwithexcluded.*, -
JSON / JSONB support, and
-
the SQL built-in functions.
-
Role: engine core (interpreter, storage, translation, functions).
-
Version: 0.3.3 (2026-07-17).
-
Tests: 888 passing with default features; 885 passing
--all-features(which already enablesindex_experimental— the small delta is a couple of feature-gated tests moving crates, not a regression); 0 failed (verified 2026-07-17). -
Approx LOC: ~87,900 (tokei, all
.rsunder this crate incl. tests; up from ~86,400 prior release). -
Pure Rust / no C: 100% Rust. No C allocator, no C parser generator, no
cc/build.rs.CC=/usr/bin/false cargo buildsucceeds. -
Known debt: ~315
.unwrap()calls remain in production code paths (concentrated instorage/,translate/,vdbe/), inherited from upstreamlimboand not new this release. This release converted several on-disk page-corruption panics to typedLimboError::Corrupterrors, but most remaining sites are untouched; tracked in the workspace-rootTODO.md. -
Internal: engine-internal member of the OxiSQL workspace (consumed via
oxisql-sqlite-compat); independently published on crates.io like every otheroxisqlite-*crate (nopublish = false; live since v0.1.0, 2026-06-11).
COOLJAPAN changes vs upstream limbo 0.0.22
Notable additions on top of the original fork:
-
Full-transaction
ROLLBACK. Ported fromturso_core0.7.0-pre.5 (MIT). Spanstranslate/rollback.rs,vdbe/execute/txn_schema.rs,storage/wal.rs, andstorage/pager.rs. -
SAVEPOINT/RELEASE/ROLLBACK TO SAVEPOINT. Full nested savepoint semantics with WAL-based page-state restoration; pager savepoint stack. -
ANALYZEstatement + System-R optimizer.translate/analyze.rsgenerates bytecode that writessqlite_stat1rows;statistics.rsloads them into aSchemaStatsside-map;translate/optimizer/cost.rsuses real selectivity when stats are present (backwards compatible — un-analyzed DBs unchanged). -
UPSERT
ON CONFLICT DO UPDATE / DO NOTHING.translate/upsert.rshandles all forms includingexcluded.*, per-target conflict routing, and theindex_experimentalunique-index path.DO UPDATE SETcan no longer target aGENERATED ALWAYS AS (...)column — rejected the same way a plainUPDATErejects it (this release). -
Schema-cookie invalidation +
SchemaChanged. DDL bumps the schema cookie;op_transactionverifies it; stale statements raiseLimboError::SchemaChanged. -
Module splits via
splitrs.schema.rs(1,920 lines) →schema/(7 files);vdbe/execute.rs(8,361 lines) →vdbe/execute/(10 files); this release addedjson/jsonb.rs→json/jsonb/,storage/pager.rs→storage/pager/,functions/datetime.rs→functions/datetime/,translate/expr.rs→translate/expr/,translate/insert.rs→translate/insert/,types.rs→types/, andutil.rs→util/— all to stay under the workspace's 2000-line-per-file policy, no functional change. Also this release:NATURAL JOINcommon-column detection rewritten from an O(n²) nested loop to aHashSetprecomputation (translate/planner.rs) — same results, better performance on wide joins. -
Pure-Rust Julian-day conversion. GPL
julian_day_converterremoved; replaced by inlinefunctions/julian_day.rs. -
CREATE TABLE ... AS SELECT(CTAS) + per-constraintON CONFLICT.translate/schema.rsexecutes the SELECT and populates the new table; column- and table-levelUNIQUEconstraints now carry their ownON CONFLICT <action>resolution (schema/column.rs,schema/table.rs,schema/index.rs). -
Compound-SELECT
INTERSECT/EXCEPT, plus compoundLIMIT/OFFSET/ORDER BYand a sharedWITH.translate/compound_select.rs. All reuse the ephemeral-unique-index dedupe machineryUNIONalready used, so — like UPSERT's unique-index path above — they require theindex_experimentalfeature. -
FROM (t1 JOIN t2 ON ...)parenthesized joins as a pure grouping construct (translate/planner.rs), and virtual-tableORDER BYpushdown —xBestIndexnow receives the query's realORDER BYcolumns and the core elides its own sorter when the vtab reportsorder_by_consumed(translate/main_loop.rs). -
x IN (...)/NOT IN (...)as a value expression, e.g.SELECT x IN (1,2,3) FROM t, not just a top-levelWHERE/JOIN ONcondition (translate/expr/value.rs). -
Open a database from an in-memory byte buffer.
Database::open_from_bytes(bytes, enable_mvcc)(lib.rs) copies asqlite3_serialize()-style image into a fresh in-memory page store (MemoryFile::from_bytes, now public —io/memory.rs) with no temp file; deliberately not gated by thefsfeature, so it works onwasm32/WASI and read-only filesystems. Malformed input (too-short header, bad magic, invalid page size) returns a typed error and never panics. -
Windows file locking (
io/windows.rs). RealLockFileEx/UnlockFileEx-backed locking via a newwindows-sysdependency, gated tocfg(target_os = "windows")so it never enters the dependency graph on other targets — previously anunimplemented!()stub. -
REGEXPoperator /regexp()function.X REGEXP Y(equivalentlyregexp(Y, X)) is now a recognized function (function.rs,translate/expr/binary_emit.rs) — an unanchoredregex-crate search, three-valuedNULLhandling, and a clean constraint error (never a panic) on a malformed pattern. -
Wider
printf()specifier coverage (functions/printf.rs).%i(alias for%d),%x/%X(hex),%o(octal),%c(first character of the argument), and%e/%E(C-style scientific notation) now work; flag/width/precision modifiers (e.g.%05d,%.3s) remain a documentedTODO.
This release also closed a substantial list of correctness bugs. Data-safety:
a B-tree index-page balance bug that could silently corrupt a page while
rebalancing an interior index page (insert_into_cell, storage/btree/);
index-based access for DELETE/UPDATE, disabled workspace-wide since an
upstream-reported corruption bug
(tursodatabase/limbo#1714),
now re-enabled behind a provable-safety check instead of an unconditional
table-scan fallback; an MVCC transaction-removal race and an MVCC
commit-ordering durability gap (a crash between marking a transaction visible
and persisting it could previously lose data); WAL checkpoint bookkeeping
that could leak unbounded frame-cache state across repeated partial
checkpoints; and on-disk page-corruption handling that now returns
LimboError::Corrupt instead of panicking on an untrusted cell/freeblock
pointer or page-type byte. SQL behavior: UPDATE ... RETURNING (previously
silently returned zero rows), ALTER TABLE RENAME on schemas containing
views/triggers/vtabs, virtual-table multi-row INSERT (previously kept only
the last row), repeated-CTE-reference resolution, SELECT COUNT(*) on an
MVCC-backed cursor (previously todo!()), wide-row varint record headers,
||/concat()/QUOTE() BLOB→TEXT coercion, strftime() %J and
pad-override flags, and PRAGMA auto_vacuum = FULL root-page tracking. A
Miri-driven memory-safety pass also reworked 40+ page-access call sites
across the storage/B-tree layers to remove simultaneous-mutable-alias
hazards, plus a pointer-provenance fix in BLOB/TEXT materialization and a
page-cache leak fix. See the repo-root CHANGELOG.md's [0.3.3] entry for
the complete list, and the workspace-root TODO.md for the highest-priority
Miri issue that remains open (B-tree rebalancing borrow lifetimes in
storage/btree/page_ops.rs/cursor_write.rs, HIGH priority, believed
data-sound in practice but not yet fixed).
Fork lineage & licensing
Part of a COOLJAPAN C-free fork of limbo 0.0.22 (MIT). Full attribution, the
upstream commit, the turso_core ROLLBACK provenance, and per-component
licensing are recorded in the repo-root /NOTICE.
Copyright © 2024–2026 COOLJAPAN OU (Team Kitasan). COOLJAPAN code is licensed
under Apache-2.0; upstream limbo code remains under MIT (see
/NOTICE).
Part of the OxiSQL workspace.