borinquenkid opened a new pull request, #16583:
URL: https://github.com/apache/grails-core/pull/16583
## Problem
`UniqueConstraint` added a condition for a property of the unique group only
when its value was not `null`. A `null` group value dropped the property from
the query, so `language unique: 'country'` checked `new Language(language:
'en')` as `where language = 'en'` and rejected it because `('en', 'US')`
exists. The same happened for the `Requestmap` (`url unique: 'httpMethod'`) of
the issue and for a self-referencing `Folder` (`name unique: 'parent'`), where
a top level folder conflicted with a folder of the same name under any parent.
This is stricter than any reading of `null`: in SQL `null` values never
conflict, and if `null` is a value it conflicts only with another `null`. All
datastores were affected.
## Fix
A `null` group value now adds `isNull(property)` to the query, so `null` is
compared as a value: `('Root', null)` conflicts only with another top level
`Root`. Non null values, the handling of unsaved to-one group members and the
`DirtyCheckable` shortcut are unchanged. The shortcut already looks at every
group property, so changing a group value to `null` triggers validation.
## Behaviour change (who is affected)
Applications that relied on a `null` group value matching every row of the
constrained property now get a successful validation when the rows differ in
the group property. The old behaviour was a defect and has no replacement. The
upgrade guide gets a new `upgrading90x` page (and a `toc.yml` entry) with this
note, and the `unique` constraint reference states the null semantics.
## Tests
- `UniqueConstraintNullGroupValueSpec` (TCK, runs on every datastore that
registers the constraint, here Hibernate 7): the `Requestmap`, `Language` and
`Folder` shapes, several nullable group members, and changing a saved row's
group value. Skipped on the simple in-memory datastore of the TCK, which does
not register the `unique` constraint.
- `UniqueConstraintSpec` in `grails-datamapping-core-test` (simple in-memory
datastore with the constraint registered): a null group value, including a
subclass.
- Red before the fix, green after. `:grails-datamapping-core` (2175 tests)
and `:grails-datamapping-core-test` (664 tests) pass; so do all `*Unique*`
specs of `:grails-data-hibernate7-core`.
Fixes #14503
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]