AbstractHydrator#iterate() may not cleanup
AFAIK, AbstractHydrator#iterate() doesn't cleanup anything as long as the iteration doesn't reach the final row.
So if I break the loop on the way like following:
foreach ($query->iterate() as $row) {
if (/* some condition */) {
break;
}
yield $row;
}
The statement cursor is never be closed anymore, this means some file-based DB (like SQLite) may not be released from locking. Or that is expected result? and these usage is wrong?
That currently is the expected result, as hydration is highly dependent on previous results, sadly :-\
I can't remember if we already did this, but each query gets its own hydrator, which mitigates the problem (garbage collection does), when the iterator is released.
@Ocramius Thanks for your quick response!
First of all, I understood that is the expected result. However, we have/use the Generator nowaday, so relying on whether iterator has reached to the final row doesn't make sense IMHO. Could we solve it in 2.x? If so I'm willing to work for this.😏😏
Could we solve it in 2.x?
No, changing this behavior will most likely cause a BC break here, so I strongly suggest that you try this against develop (3.x)
I got it. Thanks a lot!
@simPod Looping you into this very old issue here w.r.t. to toIterable.
Could we potentially solve this with a finally statement so that AbstractHydrator::cleanup is called when the iterable ends in any way?
@beberlei having a reproducible test case would help. I'll try to examine the execution flow.
The problem is here:
https://github.com/doctrine/orm/blob/5577d51c447172ff8fdb81433277e625f4945cfe/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php#L183-L192
If the loop is broken, the cleanup is not executed. One possible solution is to wrap the while into a try-finally:
try {
while (true) {
$row = $this->statement()->fetchAssociative();
if ($row === false) {
// $this->cleanup(); // done on finally
break;
}
$result = [];
// .... rest of code with yields
}
} finally {
$this->cleanup();
}
Today found exact same issue.
- consumers are running using UniqueEntity validator with custom method that uses
toIterable - because
toIterablecreates new hydrator but event-manager is shared number of onClear listeners are growing because cleanup in not called after iterating all results.