EasyCorp / EasyCorp/EasyAdminBundle

4.27.0 queries all rows in a table causing a crash

Open
#7,263 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
PHP
Stars
4.3k
Forks
1.1k
Avg merge
8d 2h
Merged PRs (30d)
11

Description

Something in 4.27.0 generates following SQL:

SELECT v0_.foo1  AS foo1_0,
       v0_.foo2  AS foo2_1,
       v0_.foo3  AS foo3_2,
       v0_.foo4  AS foo4_3,
       v0_.foo5  AS foo5_4,
       v0_.foo6  AS foo6_5,
       v0_.foo7  AS foo7_6,
       v0_.foo8  AS foo8_7,
       v0_.foo9  AS foo9_8,
       v0_.foo10 AS foo10_9,
       v0_.foo11 AS foo11_10,
       v0_.foo12 AS foo12_11,
       v0_.foo13 AS foo13_12,
       v0_.foo14 AS foo14_13,
       v0_.foo15 AS foo15_14,
       v0_.foo16 AS foo16_15,
       v0_.foo17 AS foo17_16,
       v0_.foo18 AS foo18_17
FROM foos v0_

The table has millions of rows so the app runs out of memory and crashes.

Here's a stack trace where this SQL is executed:

#0 /Users/simo/Projects/Foo/Bar/vendor/doctrine/orm/src/Query/Exec/FinalizedSelectExecutor.php(27): Doctrine\DBAL\Connection->executeQuery('SELECT v0_.foo1...', Array, Array, NULL)
#1 /Users/simo/Projects/Foo/Bar/vendor/doctrine/orm/src/Query.php(296): Doctrine\ORM\Query\Exec\FinalizedSelectExecutor->execute(Object(Doctrine\DBAL\Connection), Array, Array)
#2 /Users/simo/Projects/Foo/Bar/vendor/doctrine/orm/src/AbstractQuery.php(930): Doctrine\ORM\Query->_doExecute()
#3 /Users/simo/Projects/Foo/Bar/vendor/doctrine/orm/src/AbstractQuery.php(886): Doctrine\ORM\AbstractQuery->executeIgnoreQueryCache(NULL, NULL)
#4 /Users/simo/Projects/Foo/Bar/vendor/symfony/doctrine-bridge/Form/ChoiceList/ORMQueryBuilderLoader.php(35): Doctrine\ORM\AbstractQuery->execute()
#5 /Users/simo/Projects/Foo/Bar/vendor/symfony/doctrine-bridge/Form/ChoiceList/DoctrineChoiceLoader.php(53): Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader->getEntities()
#6 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/ChoiceList/Loader/AbstractChoiceLoader.php(29): Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader->loadChoices()
#7 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/ChoiceList/LazyChoiceList.php(56): Symfony\Component\Form\ChoiceList\Loader\AbstractChoiceLoader->loadChoiceList(Object(Closure))
#8 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/ChoiceList/Factory/DefaultChoiceListFactory.php(60): Symfony\Component\Form\ChoiceList\LazyChoiceList->getChoices()
#9 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/ChoiceList/Factory/PropertyAccessDecorator.php(178): Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory->createView(Object(Symfony\Component\Form\ChoiceList\LazyChoiceList), Array, Object(Closure), Object(Closure), NULL, NULL, Array, true)
#10 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/ChoiceList/Factory/CachingFactoryDecorator.php(202): Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator->createView(Object(Symfony\Component\Form\ChoiceList\LazyChoiceList), Array, Object(Closure), Object(Closure), NULL, NULL, Array, true)
#11 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/Extension/Core/Type/ChoiceType.php(479): Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator->createView(Object(Symfony\Component\Form\ChoiceList\LazyChoiceList), Array, Object(Closure), Object(Closure), NULL, NULL, Array, true)
#12 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/Extension/Core/Type/ChoiceType.php(234): Symfony\Component\Form\Extension\Core\Type\ChoiceType->createChoiceListView(Object(Symfony\Component\Form\ChoiceList\LazyChoiceList), Array)
#13 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/ResolvedFormType.php(107): Symfony\Component\Form\Extension\Core\Type\ChoiceType->buildView(Object(Symfony\Component\Form\FormView), Object(Symfony\Component\Form\Form), Array)
#14 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php(78): Symfony\Component\Form\ResolvedFormType->buildView(Object(Symfony\Component\Form\FormView), Object(Symfony\Component\Form\Form), Array)
#15 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/ResolvedFormType.php(105): Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorProxy->buildView(Object(Symfony\Component\Form\FormView), Object(Symfony\Component\Form\Form), Array)
#16 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php(78): Symfony\Component\Form\ResolvedFormType->buildView(Object(Symfony\Component\Form\FormView), Object(Symfony\Component\Form\Form), Array)
#17 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/Form.php(888): Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorProxy->buildView(Object(Symfony\Component\Form\FormView), Object(Symfony\Component\Form\Form), Array)
#18 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/Form.php(891): Symfony\Component\Form\Form->createView(Object(Symfony\Component\Form\FormView))
#19 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/Extension/Core/Type/CollectionType.php(64): Symfony\Component\Form\Form->createView(Object(Symfony\Component\Form\FormView))
#20 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/ResolvedFormType.php(107): Symfony\Component\Form\Extension\Core\Type\CollectionType->buildView(Object(Symfony\Component\Form\FormView), Object(Symfony\Component\Form\Form), Array)
#21 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php(78): Symfony\Component\Form\ResolvedFormType->buildView(Object(Symfony\Component\Form\FormView), Object(Symfony\Component\Form\Form), Array)
#22 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/Form.php(888): Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorProxy->buildView(Object(Symfony\Component\Form\FormView), Object(Symfony\Component\Form\Form), Array)
#23 /Users/simo/Projects/Foo/Bar/vendor/symfony/form/Form.php(891): Symfony\Component\Form\Form->createView(Object(Symfony\Component\Form\FormView))
#24 /Users/simo/Projects/Foo/Bar/vendor/easycorp/easyadmin-bundle/src/EventListener/CrudResponseListener.php(44): Symfony\Component\Form\Form->createView()
#25 /Users/simo/Projects/Foo/Bar/vendor/symfony/event-dispatcher/Debug/WrappedListener.php(115): EasyCorp\Bundle\EasyAdminBundle\EventListener\CrudResponseListener->onKernelView(Object(Symfony\Component\HttpKernel\Event\ViewEvent), 'kernel.view', Object(Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher))
#26 /Users/simo/Projects/Foo/Bar/vendor/symfony/event-dispatcher/EventDispatcher.php(206): Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(Object(Symfony\Component\HttpKernel\Event\ViewEvent), 'kernel.view', Object(Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher))
#27 /Users/simo/Projects/Foo/Bar/vendor/symfony/event-dispatcher/EventDispatcher.php(56): Symfony\Component\EventDispatcher\EventDispatcher->callListeners(Array, 'kernel.view', Object(Symfony\Component\HttpKernel\Event\ViewEvent))
#28 /Users/simo/Projects/Foo/Bar/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php(126): Symfony\Component\EventDispatcher\EventDispatcher->dispatch(Object(Symfony\Component\HttpKernel\Event\ViewEvent), 'kernel.view')
#29 /Users/simo/Projects/Foo/Bar/vendor/symfony/http-kernel/HttpKernel.php(188): Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch(Object(Symfony\Component\HttpKernel\Event\ViewEvent), 'kernel.view')
#30 /Users/simo/Projects/Foo/Bar/vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1)
#31 /Users/simo/Projects/Foo/Bar/vendor/symfony/http-kernel/Kernel.php(182): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#32 /Users/simo/Projects/Foo/Bar/vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php(35): Symfony\Component\HttpKernel\Kernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#33 /Users/simo/Projects/Foo/Bar/vendor/autoload_runtime.php(29): Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run()
#34 /Users/simo/Projects/Foo/Bar/public/index.php(9): require_once('/Users/simo/Pro...')
#35 {main}

It's the CollectionField field somehow, but doesn't happen with every CollectionField I have.

Will try to create a minimal reproducer later

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Use the CollectionField path and the ORMQueryBuilderLoader stack frame as entry points. First reproduce the 4.27.0 behavior with a CollectionField and a large table, then trace why the choice loader executes an unrestricted query. Done means the affected field no longer loads every row into memory and the crash is prevented.

Written by the indexing model from the issue text.

Assessment

Tech stack
php, symfony
Domain
backend, database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.