Beta Past initial proving, but the Python API surface may still shift before 1.0. WiredTiger on-disk format is stable, but there's no migration tool yet — don't put production data here.

A silent lost update caught in the act, pipelined batches with real transaction semantics, and query cancellation

15 August 2026 · Joe Drumgoole · Releases

Summary: A silent lost update caught in the act, pipelined batches with real transaction semantics, and query cancellation (v0.6.0b11).

The headline of this release is a data-integrity fix that took three CI platforms, a paired A/B sampler, and a deterministic race harness to pin down. Statements a client pipelines before a single Sync now run in one implicit transaction, exactly as PostgreSQL treats them — pgjdbc's 184-variant BatchFailureTest depends on a failed batch rolling back its earlier inserts, and both batch classes now pass in full. Making that correct exposed a genuine race: an implicit transaction's commit lands outside the statement lock, and a concurrent autocommit computed update (SET n = n + 1) whose read-compute-write window it straddled would silently overwrite it while still reporting UPDATE 1. The fix runs the whole computed update as one storage snapshot transaction, so a mid-window commit surfaces as a write conflict and the statement retries from a fresh read — proven by a paired fix-on/fix-off sampler catching the loss in the wild on the exact runner conditions that first exposed it.

The PostgreSQL surface took two more long-standing steps. The wire cancel sub-protocol is honoured — a CancelRequest verifies the BackendKeyData secret and interrupts the target's running statement with PG's 57014, which is what JDBC's setQueryTimeout and pgx's context cancellation lean on. And named prepared statements revalidate their cached plan under DDL, raising cached plan must not change result type with the routine field pgjdbc's transparent re-prepare matches on — its 1056-variant AutoRollbackTest matrix now passes in full. Around them: dollar-quoted strings and nested block comments parse everywhere, CREATE TABLE AS SELECT works, now() is transaction-stable, LISTEN/NOTIFY pushes to idle connections asynchronously, and per-session temp-table namespacing matches PG's pg_temp_<n> scheme.

On the MongoDB side, the default getMore batch now fills mongod's 16MB envelope instead of stopping at 101 documents — a large cursor drain that took dozens of round trips now takes one — and retryable writes are idempotent across reconnects on both servers, with failGetMore carrying the resumable-error label change streams expect.

Prepared statements revalidate their cached plan, like Postgres

A named server-prepared statement whose result shape changed under DDL (a SELECT * after ALTER TABLE ADD COLUMN) now raises PostgreSQL's cached plan must not change result type (0A000) instead of silently re-planning — and it raises at planning time, before any side effect, so a data-modifying CTE's INSERT does not run. The ErrorResponse carries ROUTINE=RevalidateCachedQuery, which is the field (not the SQLSTATE) pgjdbc's transparent re-prepare-and-retry matches on; without it every recoverable case surfaced the raw error. Unnamed statements re-plan per Bind and never raise, matching PG. pgjdbc's AutoRollbackTest — the 1056-variant autosave × DDL × transaction matrix — now passes in full.

Full release notes on GitHub · Install from PyPI · Tag