orm icon indicating copy to clipboard operation
orm copied to clipboard

AbstractHydrator#iterate() may not cleanup

Open issei-m opened this issue 8 years ago • 8 comments

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?

issei-m avatar May 31 '17 07:05 issei-m

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 avatar May 31 '17 09:05 Ocramius

@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.😏😏

issei-m avatar May 31 '17 11:05 issei-m

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)

Ocramius avatar May 31 '17 11:05 Ocramius

I got it. Thanks a lot!

issei-m avatar May 31 '17 13:05 issei-m

@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 avatar Dec 08 '20 01:12 beberlei

@beberlei having a reproducible test case would help. I'll try to examine the execution flow.

simPod avatar Feb 05 '21 18:02 simPod

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();
        }

JoniJnm avatar Aug 17 '23 16:08 JoniJnm

Today found exact same issue.

  1. consumers are running using UniqueEntity validator with custom method that uses toIterable
  2. because toIterable creates new hydrator but event-manager is shared number of onClear listeners are growing because cleanup in not called after iterating all results.

oleg-andreyev avatar Apr 19 '24 10:04 oleg-andreyev