Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- A migration that uses a column type the database adapter doesn't map (for example `t.column(columnName="payload", columnType="jsonb")`) now fails at migrate time with `Wheels.Migrator.UnsupportedColumnType`, naming the type and the adapter and listing the supported types, instead of emitting a column with no type; that typeless column was a DDL syntax error on most databases, a raw missing-key error on Oracle, and on SQLite a column whose model failed to load (#4095).
- A migration that uses a column type the database adapter doesn't map (for example `t.column(columnName="payload", columnType="jsonb")`) now fails at migrate time with `Wheels.Migrator.UnsupportedColumnType`, naming the type and the adapter and listing the supported types, instead of emitting a column with no type; that typeless column was a DDL syntax error on most databases, a raw missing-key error on Oracle, and on SQLite a column whose model failed to load (#4095)
2 changes: 1 addition & 1 deletion changelog.d/4134-migration-lock.changed.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- Instances that share a database now run its migrations one at a time: `migrateTo()`, `migrateToLatest()`, `migrateIndividual()` and `redoMigration()` hold a cross-process lock, a lease row in the new `wheels_migrator_locks` table, on every supported database. An instance that waits re-reads which migrations are pending once it has the lock, so it doesn't run them again. It gives up after `migrationLockTimeout` (default 300 seconds) with `Wheels.MigrationLockTimeout`, naming the host holding the lock. The lease (`migrationLockLease`, default 3600 seconds) is renewed before each migration step, and a holder that died frees the lock when its lease runs out; a single migration step that runs longer than the lease can lose the lock to another instance (`Wheels.MigrationLockLost`). To clear a stuck lock at once, run `wheels migrate unlock --force` or delete its row from `wheels_migrator_locks` (#4134).
- Instances that share a database now run its migrations one at a time: `migrateTo()`, `migrateToLatest()`, `migrateIndividual()` and `redoMigration()` hold a cross-process lock, a lease row in the new `wheels_migrator_locks` table, on every supported database. An instance that waits re-reads which migrations are pending once it has the lock, so it doesn't run them again. It gives up after `migrationLockTimeout` (default 300 seconds) with `Wheels.MigrationLockTimeout`, naming the host holding the lock. The lease (`migrationLockLease`, default 3600 seconds) is renewed before each migration step, and a holder that died frees the lock when its lease runs out; a single migration step that runs longer than the lease can lose the lock to another instance (`Wheels.MigrationLockLost`). To clear a stuck lock at once, run `wheels migrate unlock --force` or delete its row from `wheels_migrator_locks` (#4134)
2 changes: 1 addition & 1 deletion changelog.d/4149-controller-construction.performance.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- Creating a controller instance, which happens on every request, no longer mixes the framework's controller and view methods in one at a time. Each controller class works out once which methods to add and which `super<name>` aliases to create, and every later instance applies that result with two `StructAppend` calls. Measured per instance in the same process: 4.8 ms → 1.4 ms on RustCFML (the CI-pinned v0.693.0), 2.3 ms → 0.9 ms on Adobe ColdFusion 2023, 1.7 ms → 0.8 ms on Adobe ColdFusion 2025, 0.58 ms → 0.33 ms on Lucee 7 and 4.7 ms → 3.6 ms on BoxLang. Development keeps the old per-method path, so controller methods edited there still take effect without a reload; the new `cacheControllerIntegration` setting controls it (#4149).
- Creating a controller instance, which happens on every request, no longer mixes the framework's controller and view methods in one at a time. Each controller class works out once which methods to add and which `super<name>` aliases to create, and every later instance applies that result with two `StructAppend` calls. Measured per instance in the same process: 4.8 ms → 1.4 ms on RustCFML (the CI-pinned v0.693.0), 2.3 ms → 0.9 ms on Adobe ColdFusion 2023, 1.7 ms → 0.8 ms on Adobe ColdFusion 2025, 0.58 ms → 0.33 ms on Lucee 7 and 4.7 ms → 3.6 ms on BoxLang. Development keeps the old per-method path, so controller methods edited there still take effect without a reload; the new `cacheControllerIntegration` setting controls it (#4149)
2 changes: 1 addition & 1 deletion changelog.d/4172-wide-decimal-exact-bind.fixed.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- A `DECIMAL` / `NUMERIC` value with more than 15 significant digits is now stored and matched in a `where` exactly on PostgreSQL, SQL Server, MySQL and CockroachDB under Lucee and BoxLang, which bound it through a double and so wrote or compared a different number; such a value now binds in each database's exact form, and values with up to 15 significant digits keep their existing bind (#4172).
- A `DECIMAL` / `NUMERIC` value with more than 15 significant digits is now stored and matched in a `where` exactly on PostgreSQL, SQL Server, MySQL and CockroachDB under Lucee and BoxLang, which bound it through a double and so wrote or compared a different number; such a value now binds in each database's exact form, and values with up to 15 significant digits keep their existing bind (#4172)
2 changes: 1 addition & 1 deletion changelog.d/4174-promote-globals-metadata.performance.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- Creating any model object or controller no longer calls `GetMetadata(this)` while the object is being constructed. The memo of include-injected functions to promote to `this` always ended up under one entry (`wheels.Global`) on every supported engine, so it now uses that key directly. On RustCFML the call cost about 225 µs per object; model `new()` went from 1.30 ms to 1.13 ms there, and from 0.31 ms to 0.25 ms on Lucee 7 (#4174).
- Creating any model object or controller no longer calls `GetMetadata(this)` while the object is being constructed. The memo of include-injected functions to promote to `this` always ended up under one entry (`wheels.Global`) on every supported engine, so it now uses that key directly. On RustCFML the call cost about 225 µs per object; model `new()` went from 1.30 ms to 1.13 ms there, and from 0.31 ms to 0.25 ms on Lucee 7 (#4174)
2 changes: 1 addition & 1 deletion changelog.d/4187-singularize-prefixed-analyses.changed.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- `singularize()` returns `psychoanalysis` for `psychoanalyses` instead of the misspelled `psychoanalyasis`; other `-ses` words such as `bases`, `theses` and `analyses` are unchanged (#4187).
- `singularize()` returns `psychoanalysis` for `psychoanalyses` instead of the misspelled `psychoanalyasis`; other `-ses` words such as `bases`, `theses` and `analyses` are unchanged (#4187)
2 changes: 1 addition & 1 deletion changelog.d/4189-singularize-databases.changed.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- `singularize("databases")` returns `database` instead of `databasis`, so a name such as `Databases` or `userDatabases` now singularizes to `Database` / `userDatabase`. An app that relied on the old `databasis` output, for example a model class or table named after it, needs to rename it. That's unlikely, but check before upgrading. Other `-ases` words (`bases`, `cases`, `phases`, `purchases`, `vases`) are unchanged (#4189).
- `singularize("databases")` returns `database` instead of `databasis`, so a name such as `Databases` or `userDatabases` now singularizes to `Database` / `userDatabase`. An app that relied on the old `databasis` output, for example a model class or table named after it, needs to rename it. That's unlikely, but check before upgrading. Other `-ases` words (`bases`, `cases`, `phases`, `purchases`, `vases`) are unchanged (#4189)
2 changes: 1 addition & 1 deletion changelog.d/oracle-beyond-64bit.fixed.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- On Oracle, a whole number beyond the signed 64-bit range (more than 9,223,372,036,854,775,807, or less than -9,223,372,036,854,775,808) written to or compared against a `NUMBER` column is now bound as text, which Oracle converts exactly. It was clamped (Lucee), wrapped (BoxLang) or rounded through a double, so it could be stored or matched as a different number (#4162).
- On Oracle, a whole number beyond the signed 64-bit range (more than 9,223,372,036,854,775,807, or less than -9,223,372,036,854,775,808) written to or compared against a `NUMBER` column is now bound as text, which Oracle converts exactly. It was clamped (Lucee), wrapped (BoxLang) or rounded through a double, so it could be stored or matched as a different number (#4162)
2 changes: 1 addition & 1 deletion changelog.d/tx-advisory-locks.added.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- `withAdvisoryLock()` now accepts an opt-in `transaction = true` argument that pins the lock acquire, the callback, and the release to one connection inside a transaction, so the lock genuinely covers the callback's own queries. On PostgreSQL the lock is transaction-scoped and auto-releases when the transaction ends; on MySQL and SQL Server it is a session lock released before the transaction closes. Supported on PostgreSQL, MySQL, and SQL Server; other databases throw rather than silently running session-scoped. Recommended for short critical sections — a long-running callback holds its row locks and a pooled connection (and blocks PostgreSQL VACUUM) for the whole call. Defaults to `false` (the existing behaviour). ([#4198](https://github.com/wheels-dev/wheels/issues/4198)).
- `withAdvisoryLock()` now accepts an opt-in `transaction = true` argument that pins the lock acquire, the callback, and the release to one connection inside a transaction, so the lock genuinely covers the callback's own queries. On PostgreSQL the lock is transaction-scoped and auto-releases when the transaction ends; on MySQL and SQL Server it is a session lock released before the transaction closes. Supported on PostgreSQL, MySQL, and SQL Server; other databases throw rather than silently running session-scoped. Recommended for short critical sections — a long-running callback holds its row locks and a pooled connection (and blocks PostgreSQL VACUUM) for the whole call. Defaults to `false` (the existing behaviour). ([#4198](https://github.com/wheels-dev/wheels/issues/4198))
Loading