Experiment 144: sqlite3mc 2.3.2 → 2.3.5 bump (SQLite 3.51.3 → 3.53.2)

Date: 2026-06-08

Status: In Review

Direction:sqlite-version-and-build-config

Problem

Exp 090 rejected a sqlite3mc bump from

2.3.2 to 2.3.3 because 2.3.3 packaged SQLite 3.53.0 — a 12-day-old .0

release excluded by the known-regressions policy. Its revisit trigger

named the exact follow-up condition:

> Re-run this investigation when SQLite 3.53.2 (or later .2+) ships

> upstream, and sqlite3mc cuts a release tracking it.

Both halves of that trigger are now true. SQLite shipped 3.53.2 on

2026-06-03 (after 3.53.1 on 2026-05-05 stabilised the 3.53.x line), and

sqlite3mc 2.3.5 packaged 3.53.2 on 2026-06-05. The vendored copy is now

~2.5 months behind upstream — the audit window exp 090 promised to

reopen.

Hypothesis

A current sqlite3mc with a soaked .2 SQLite point release lands cleanly

on resqlite's release suite. The 3.53.0 planner work and reimplemented

float-to-text path may produce small wins on simple writes/inserts; .1 +

.2 are stability fixes. No targeted regression should appear on the

release-suite write or stream workloads.

Accept if focused validation passes (dart test, dart analyze) and

the release peer comparison stays neutral-or-better on the chartable

metrics, with any single-run regression flag either collapsing under

rerun or being small enough that the soak window can resolve it. Reject

(hold at 2.3.2) if a release-suite hot metric regresses consistently

across multiple passes with no plausible cause-fix.

Approach

  1. Verified exp 090's two revisit conditions are satisfied:
  2. SQLite 3.53.2 shipped 2026-06-03 (SQLITE_SOURCE_ID `2026-06-03

19:12:13 d6e03d8c777cfa2d35e3b60d8ec3e0187f3e9f99d8e2ee9cac695fd6fcdf1a24`).

schema join order, EXISTS-to-JOIN, omit-noop-join chains): low

expected impact — resqlite's hot path is point queries + simple

inserts, not multi-way joins.

reads REAL via sqlite3_column_double and formats with its own

snprintf("%.17g", ...) in native/resqlite.c rather than going

through sqlite3_column_text. The 15→17-digit default-rounding

hazard exp 090 flagged for snapshot tests cannot reach resqlite's

output bytes.

etc.): additive; no FFI signature change.

defines exp 090 audited against 3.53.0).

  1. Vendored the new files:
  2. sqlite3mc_amalgamation.c/.h from the v2.3.5 amalgamation zip.
  3. sqlite3.h/sqlite3ext.h from sqlite-amalgamation-3530200

(upstream SQLite 3.53.2 source).

SHA-256s.

  1. Skipped the SQLITE_DBCONFIG_FP_DIGITS = 15 shim exp 090's

step-by-step plan called out. Since resqlite never serialises REAL

via sqlite3_column_text, pinning pre-3.53 FP rounding would be a

no-op on the output path and add unnecessary connection-init work.

Results

Validation

Unicode/embedded-NUL executeBatch regression tests, transaction

read/write semantics, blob round-trips, and the foreign-key default

assertions — the surface most likely to expose a SQLite behavior

change.

Release suite A/B

Single-pass benchmark/run_release.dart against sqlite3mc 2.3.2

baseline. Two independent single-run candidate passes against the same

baseline were taken to separate persistent signal from single-run noise.

Canonical run (2026-06-08T07-34-23-exp144-sqlite3mc-2-3-5): 19

wins, 18 regressions, 124 neutral.

Confirmation noise-check pass (re-run on the same vendored

worktree): 30 wins, 2 regressions, 129 neutral.

The wide spread between the two passes (-3 net wins vs +28 net wins) is

characteristic of single-run release-suite noise at this granularity.

The reliable extraction is to look only at metrics that flagged

consistently across both candidate passes:

MetricBaseline 2.3.2Cand 1 (07-34-23)Cand 2 (confirm)Cand 3 (confirm2)
Point Query / qps102,70287,32199,014101,111
Concurrent Reads 8× / wall median ms0.750.890.920.94
Single Inserts (100) / ms2.0982.010
Long-Text Unchanged Fanout / ms3.123.472.725
No-Streams Write Throughput / ms4.385.854.067
Growing-Stream Invalidation / ms0.630.810.587

pass is read alongside the two follow-ups.

Growing-Stream Invalidation all flagged regressed on cand 1 but

beat baseline on cand 2 — pure single-run variance.

slower across every candidate pass (+19 % / +23 % / +25 %). Per-query

latency is 0.09 → 0.11–0.12 ms — small in absolute terms, but the

direction is monotonic, so this needs multi-pass confirmation in the

soak window. The 4× concurrency case wins by 12-21 % on the same

baseline, so it is not a generic read-pool slowdown.

+1,400 across the two passes — same coalescing-sensitive metric that

the disjoint_columns benchmark docstring (exp 045) calls out as

highly timing-dependent.

Decision

Accept for review. The bump satisfies exp 090's revisit trigger

exactly (.2+ SQLite + sqlite3mc tracking it), tests stay green

including the embedded-NUL and Unicode bind regression suite, and the

release-suite A/B shows that the only metric that regresses consistently

across reruns is Concurrent Reads at 8× concurrency (+~20 % on a sub-ms

metric).

The two-week soak window is the right place to confirm whether the 8×

Concurrent Reads slowdown is a real 3.53.x reader-pool interaction or

single-run tail noise that washes out in multi-pass aggregates.

Everything else flagged in the canonical run is noise — confirmation

passes show the metrics swinging in both directions around baseline.

If the 8× Concurrent Reads regression survives a multi-pass release run

during soak, this experiment should be reverted to 2.3.2 pending a

follow-up investigation into the SQLite 3.53.0 planner / connection

commit-path interactions with our concurrent reader workload.

Future Notes

SQLITE_LIMIT_PARSER_DEPTH APIs added in 3.53.0 are now available

but unused. None have a current resqlite consumer; leave the audit

until a workload actually asks for one.

signals only. The first pass on this worktree showed 19/18/124, the

rerun 30/2/129 — only metrics that flag consistently across two

independent passes are real candidate signals.

a 3.54.x.2+ point release, or a SQLite changelog item that maps

to a measured resqlite hot path (planner change relevant to point

queries, prepared-stmt path optimization, bind path optimization).