v2.9.16-beta
Pre-releaseMySQL client compatibility release. Found by driving LLDAP 0.6.3 (Rust, sqlx + sea-orm) against a live Marmot node and auditing the paths it exercised. 21 defects fixed, each covered by tests that fail on the prior code.
Data correctness
- Tables with no declared
PRIMARY KEYcould not replicateUPDATE/DELETE. Rowid is now the replicated identity. - BLOB columns silently became TEXT on every replica — would have corrupted password hashes and UUID columns. Storage class is now decided at capture time from column affinity.
- Segfault on DML against tables with
VIRTUALgenerated columns. Capture now refuses these tables cleanly. PRAGMA table_inforenumbers column ids when hidden columns exist, silently breaking primary-key indexing. Now uses truetable_xinfopositions.- A forwarded-session eviction racing a slow
COMMITcould discard a write while reporting success. Eviction now serializes against in-flight statements, andCOMMITfails loudly if its state disappears. - Schema-reload failures after DDL are no longer swallowed; count mismatches fail loud instead of truncating.
Interactive transactions
DML inside BEGIN...COMMIT now executes immediately against a pinned SQLite transaction instead of being buffered until COMMIT behind a fabricated result. Clients get real rows-affected and last_insert_id, and can read their own uncommitted writes. CDC is captured incrementally and replayed through the existing 2PC path.
New transaction.ddl_implicit_commit (default true): DDL commits the open transaction, matching MySQL.
SQL transpilation
- Partially-parsed DDL is rejected instead of being forwarded truncated into 2PC.
HAVINGwas being emitted asWHERE, breaking everyGROUP BY ... HAVINGquery.- Index DDL unified:
ADD CONSTRAINT UNIQUE,ADD INDEX,ADD UNIQUEand standaloneCREATE [UNIQUE] INDEXall emit valid SQLite;DROP INDEX ... ONis handled. CHARACTER SET/COLLATEstripped onALTER TABLE ADD/MODIFY/CHANGE COLUMN.
MySQL wire protocol
COM_STMT_PREPAREreported zero columns —sqlxbuilds its column index from that response, so prepared queries could not find their columns. This was the cause of the originally reported client panic.- Column types inferred from data and declared types instead of always
VAR_STRING; correcttime.Timeand binaryDATETIMEencoding. SERVER_STATUS_IN_TRANSis now reported.COM_STMT_SEND_LONG_DATAandCOM_STMT_RESETimplemented; previously they drew an ERR packet that desynced the connection.- Unsigned parameter flag honored, with a proper out-of-range error above
MaxInt64.
Parameter handling
Prepared statements against auto-increment tables failed with not enough args to execute query: want 6 got 5, because literal extraction turns the injected id into a placeholder while execution sites used either wire params or extracted params, never both. Parameters are now merged positionally by per-placeholder provenance.
Upgrading
No migration required. transaction.ddl_implicit_commit defaults to true (MySQL-compatible); set it to false to keep DDL inside the transaction and replicate it atomically, accepting that DML in that transaction cannot see the pending schema change.
Known limitation
Generated AUTO_INCREMENT ids are 53-bit (default) or 64-bit and overflow applications that model ids as 32-bit integers — see #170.