Repository navigation
9.40.0
Full notes: Upgrading to 9.40
No breaking changes. The whole 9.39.0 → 9.40.0 public surface was audited: nothing public was removed, and the one new interface member carries a default implementation.
⚠️ A host stop no longer waits out the advisory lock
Weasel.Postgresql.AdvisoryLock.DisposeAsync released its locks one at a time, unbounded and unlogged. With session-scoped multiplexed locks plus lock monitoring, a host stop could take 60 or 120 seconds with nothing logged at all — Medallion's connection monitor parks a connection in a one-minute wait, and the last release on it fires no wake-up because the handle drops its monitoring registration before running pg_advisory_unlock.
Releases now run concurrently and the wait is bounded by the new AdvisoryLockOptions.ReleaseTimeout (default 5s), with any overrun logged.
This changes what DisposeAsync waits for — it now returns after the timeout with outstanding releases backgrounded. Nothing leaks, and it is strictly better than the old stall, but set ReleaseTimeout to Timeout.InfiniteTimeSpan (or any non-positive value) to opt out.
A creation script runs — and re-runs
#677 · #680 · #681 · #685 · #686 · #687
The migration path has deferred foreign keys to tables created later for a long time. The script path wrote objects in yield order, so the same model could migrate cleanly and emit a script that failed on its first constraint. ToDatabaseScript() and WriteScriptsByTypeAsync() now order objects and features by dependency — features too, because WriteScriptsByTypeAsync puts each in its own file, so there the feature order is the script order.
A second run then failed on the foreign key itself. Measured on all six providers; three were already right:
| PostgreSQL | now catches duplicate_object |
| Oracle | now checks all_constraints |
| MySQL | now declares the key inline in CREATE TABLE |
| SQL Server, Firebird, SQLite | already guarded |
MySQL's rendered CREATE TABLE changes shape: foreign keys move inside the parentheses and no trailing ALTER TABLE … ADD CONSTRAINT is emitted. Identical schema, delta detection unaffected — but if you assert on that text, it moved.
All creation-path only. Every WriteAddStatement is untouched, so no rendered migration changes.
ICommandBuilder.ParameterCount
How many parameters the command being built already carries, so a caller rendering a value list can decide against Migrator.MaxParametersPerCommand instead of guessing. The budget belongs to the command, not the fragment, so a per-fragment threshold does not close the hole.
If you implement ICommandBuilder, you need change nothing. It has a default implementation returning ICommandBuilder.UnknownParameterCount (-1). Without that default this would have been a runtime break — the CLR refuses the type the first time a host loads it, which no build or restore reveals.
New public API
AdvisoryLockOptions.ReleaseTimeoutICommandBuilder.ParameterCount/UnknownParameterCountWeasel.Core.Migrations.ISchemaObjectWithDependencies— declare a creation-order dependency that is not a foreign keyWeasel.Core.Migrations.SchemaObjectOrdering.InDependencyOrderForeignKey.WriteGuardedAddStatement(PostgreSQL, Oracle),ForeignKey.WriteInlineDefinition/ToInlineDefinition(MySQL)