jamesfredley commented on code in PR #16820:
URL: https://github.com/apache/grails-core/pull/16820#discussion_r4482774478
##########
grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/query/criteria/AbstractDetachedCriteria.groovy:
##########
@@ -871,21 +922,91 @@ abstract class AbstractDetachedCriteria<T> implements
Criteria, Cloneable {
@Override
@CompileStatic
AbstractDetachedCriteria<T> clone() {
- AbstractDetachedCriteria criteria = newInstance()
- criteria.@criteria = new ArrayList(this.criteria)
- final projections = new ArrayList(this.projections)
- criteria.@projections = projections
- criteria.projectionList = new DetachedProjections(projections)
- criteria.@orders = new ArrayList(this.orders)
- criteria.defaultMax = defaultMax
- criteria.defaultOffset = defaultOffset
- criteria.@fetchStrategies = new HashMap<>(this.fetchStrategies)
- criteria.@joinTypes = new HashMap<>(this.joinTypes)
- criteria.@junctions = new ArrayList(this.junctions)
- criteria.@connectionName = this.connectionName
- criteria.@lazyQuery = this.lazyQuery
- criteria.@associationCriteriaMap = new
LinkedHashMap<>(this.associationCriteriaMap)
- return criteria
+ // a copy carries the result of the deferred query, never the query:
it runs once, here or earlier, and
+ // waits for a run on another thread, so that a copy is never half
built
+ applyLazyCriteria()
+ synchronized (this) {
+ AbstractDetachedCriteria criteria = newInstance()
+ Map<DetachedAssociationCriteria, DetachedAssociationCriteria>
associationCopies = new IdentityHashMap<>()
+ List<Query.Criterion> clonedCriteria = new
ArrayList<>(this.criteria.size())
+ for (Query.Criterion criterion : this.criteria) {
+ clonedCriteria.add(copyCriterion(criterion, associationCopies))
+ }
+ criteria.@criteria = clonedCriteria
+ criteria.@alias = this.alias
+ final projections = new ArrayList(this.projections)
+ criteria.@projections = projections
+ criteria.projectionList = criteria.newProjectionList(projections)
+ criteria.@orders = new ArrayList(this.orders)
+ criteria.defaultMax = defaultMax
+ criteria.defaultOffset = defaultOffset
+ criteria.@fetchStrategies = new HashMap<>(this.fetchStrategies)
+ criteria.@joinTypes = new HashMap<>(this.joinTypes)
+ criteria.@junctions = new ArrayList(this.junctions)
+ criteria.@connectionName = this.connectionName
+ criteria.@lazyQuery = this.lazyQuery
Review Comment:
buildLazy { sort('name') } clones the criteria while the deferred closure is
still running. The clone copies that closure and has no guard, so sort reads
the orders and runs the closure again, until the query throws
StackOverflowError. A clone made during that run must not carry the running
closure.
--
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]