borinquenkid opened a new pull request, #16822:
URL: https://github.com/apache/grails-core/pull/16822
Fixes #16805
Stacked on #16821 (chain: #16816, #16817, #16818, #16820, #16821). `no ci`
until the chain reaches 8.0.x.
## Problem
`deleteAll()` and `updateAll(Map)` on a query run one HQL statement that has
no `LIMIT`. A query with `max` or `offset` therefore wrote to **every**
matching row: `Person.where { age > 18 }.max(2).deleteAll()` deleted all of
them. The HQL builder behind these statements also had gaps:
- a subquery with two criteria produced `... < :p2age > :p3` (no `AND`),
which does not parse;
- the position returned for an association criterion was dropped, so a
parameter after it reused a number;
- `exists`, `notExists`, a to-one association, an alias and `sqlRestriction`
were refused.
## Changes
- `HibernateSession.deleteAll` / `updateAll` throw
`InvalidDataAccessResourceUsageException` for `max` or `offset` and write
nothing. `QueryableCriteria` gets `getDefaultMax()` / `getDefaultOffset()`
(default `null`) for the check.
- `JpaQueryBuilder`:
- joins a subquery's criteria with `AND`, and drops `WHERE` when it has
none;
- keeps the parameter position after an association criterion;
- writes `Exists` / `NotExists`;
- writes a to-one association (block, dotted path, `createAlias` alias) as
`owner.id IN (SELECT ...)`, since HQL DML cannot join. A to-many association is
still refused with the same message;
- `registerHqlRenderer` lets a datastore render a criterion type it adds.
Hibernate 7 registers `SqlRestrictionHqlRenderer`, which calls the existing
`grails_sql_restriction` function, so `{alias}` and `?` work.
- `Query.PropertyNameCriterion.withProperty(String)` copies a criterion onto
another property, used to split `owner.name`.
- Two existing specs pinned the old behavior and are updated:
`JpaQueryBuilderFunctionSpec` expected the missing `AND`, and
`HibernateCriteriaBuilderSqlRestrictionSpec` expected `sqlRestriction` to be
refused in a batch operation.
## Tests
- `BulkWritePaginationGuardSpec` (8): max, offset, both, derived criteria,
delete by selected ids, and the unpaginated control. Red before the fix (6
failures).
- `BulkWriteQueryShapesSpec` (17): subqueries, deferred subquery, exists,
notExists, to-one block, path, alias, position after an association,
`sqlRestriction` with `{alias}`, `?` and a quoted literal. Red before the fix
(9 failures).
- `JpaQueryBuilderBulkWriteSpec` (13): the exact HQL and parameters, a
registered renderer, and an unknown criterion.
- `SqlRestrictionHqlRendererSpec` (7).
- Full suites pass for `grails-datastore-core`, `grails-datamapping-core`,
`grails-datamapping-core-test`, `grails-data-hibernate7-core` and
`grails-data-hibernate5-core`; `codeStyle`, `validateRepositoryConventions` and
`rat` are clean.
## Not covered
- PITest on `JpaQueryBuilder` (run with #16819's `mutableProjects`, from
`grails-datamapping-core-test`): no mutant survives in the methods this PR
added, except `dot <= 0` in `splitToOnePath`, which is an equivalent mutant (an
empty head name matches nothing). The older methods of the class keep their
uncovered mutants (for example `functionOperator`); they are not part of this
change.
- A dotted alias path such as `createAlias('owner.address', 'a')` is not
resolved in a bulk write; it is refused with the property error.
## Docs
8.0 upgrade guide section 26.14, the CRUD guide note, and the
`grails-8-upgrade` skill.
--
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]