Skip to content

9.36.0

Choose a tag to compare

@jeremydmiller jeremydmiller released this 29 Sep 13:19
· 28 commits to master since this release
c3c74a4

A drift release, and one new diagnostic.

Most of 9.36.0 is a single shape of defect found five times over: a model declares something in a spelling the server rewrites when it stores it, so the column or index never matches itself, every migration re-issues DDL that changes nothing, and the delta never settles. MySQL type synonyms, Oracle ANSI type names, Oracle and MySQL index key direction, Oracle index tablespaces and SQL Server CAST all did this.

📖 Full upgrade notes

Read this before upgrading

Oracle: a table with a string column default could not be created at all under the default CreateIfNotExists style — the quote ended the EXECUTE IMMEDIATE literal and the create failed with PLS-00103 (#643).

Two migrations change behaviour. Changing a computed column's definition now drops and recreates the indexes and foreign keys that depend on it (#638). That migration used to fail outright on SQL Server, and used to succeed while silently dropping the index on PostgreSQL.

Every drift fix was checked in both directions. The spellings that already reconciled still reconcile, and a genuinely different type, length or direction is still reported as drift. No settled table acquires a new ALTER.

JasperFx 2.76.0 is the new floor, the first release carrying the IAdvisoryLock.FindHolderAsync contract.

Who holds this advisory lock?

#650. IAdvisoryLock could acquire a distribution lock but not say who holds it — HasLock(lockId) answers only "does this node". So when a projection agent stopped with ProgressionProgressOutOfOrderException, meaning two processes believed they owned the same shard, nothing could name the other one. Under Marten HotCold and Polecat the lock is the authority.

var holder = await advisoryLock.FindHolderAsync(lockId, token);
// null means unheld; IsCurrentNode == false means someone else has it

Both reads were measured against live servers rather than inferred, and one measurement changed the implementation: pg_locks stores the advisory key as two 32-bit halves, so a negative lock id sign-extends into classid = 0xFFFFFFFF. The obvious query reports a held lock as unheld — precisely the reassuring answer an operator chasing a double-runner must never be handed.

Everything else

Area Issues
Oracle — respelled column types (every TimeSpan drifted), index direction, index tablespace, guarded-DDL quotes #649 #645 #644 #643
MySQL — type synonyms, index direction, IgnoreIndex honoured, CREATE DATABASE only when missing #646 #641 #642 #647
SQLite — add-only rebuilds keep undeclared objects, rollbacks keep rows, PreserveIdentifierCase, sqlite_sequence #639 #648 #640 #546
SQL Server — CAST reconciles against the stored CONVERT; computed-column dependants #637 #638
Contributing — one npm dependency tree for the docs #582

Two SQLite fixes are the default for any EF Core model, since MapToTable sets both AddOnlyMigrations and PreserveIdentifierCase: a rebuild no longer drops the columns the model does not declare (and their rows), and a PreserveIdentifierCase table no longer renames every column to itself on every single migration.

#546 had been open since 9.29.0, where it shipped as a known issue.

New public API

  • IndexDefinition.DescendingColumns on MySQL and Oracle, matching SQL Server's
  • Migrator.GenerateDeleteAllSqlAsync, a connection-aware overload defaulting to the existing behaviour
  • IAdvisoryLock.FindHolderAsync implemented on PostgreSQL and SQL Server

Thanks to @lahma for eleven of the seventeen commits.