diff --git a/phpstan-dbal2.neon b/phpstan-dbal2.neon index 47c7a5457ca..31f0f2823ab 100644 --- a/phpstan-dbal2.neon +++ b/phpstan-dbal2.neon @@ -10,6 +10,8 @@ parameters: - '/Call to an undefined method Doctrine\\DBAL\\Connection::createSchemaManager\(\)\./' # Class name will change in DBAL 3. - '/^Class Doctrine\\DBAL\\Platforms\\PostgreSQLPlatform not found\.$/' + - '/^Class Doctrine\\DBAL\\Platforms\\AbstractMySQLPlatform not found\.$/' + - '/^Class Doctrine\\DBAL\\Platforms\\MySQLPlatform not found\.$/' - message: '/Doctrine\\DBAL\\Platforms\\MyS(ql|QL)Platform/' path: src/Mapping/ClassMetadataFactory.php diff --git a/phpstan-persistence2.neon b/phpstan-persistence2.neon index 7da96fb7d4c..de49a183766 100644 --- a/phpstan-persistence2.neon +++ b/phpstan-persistence2.neon @@ -27,6 +27,9 @@ parameters: - message: '/^Call to static method ensure\(\) on an unknown class Doctrine\\DBAL\\ForwardCompatibility\\Result\.$/' path: src/Internal/Hydration/AbstractHydrator.php + - + message: '/^Instanceof between Doctrine\\DBAL\\Platforms\\AbstractPlatform and Doctrine\\DBAL\\Platforms\\MySQLPlatform will always evaluate to false\.$/' + path: src/Utility/LockSqlHelper.php # False positive - diff --git a/phpstan.neon b/phpstan.neon index 073376e99f6..c47790fef18 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -27,6 +27,9 @@ parameters: - message: '/^Call to static method ensure\(\) on an unknown class Doctrine\\DBAL\\ForwardCompatibility\\Result\.$/' path: src/Internal/Hydration/AbstractHydrator.php + - + message: '/^Instanceof between Doctrine\\DBAL\\Platforms\\AbstractPlatform and Doctrine\\DBAL\\Platforms\\MySQLPlatform will always evaluate to false\.$/' + path: src/Utility/LockSqlHelper.php # False positive - diff --git a/psalm.xml b/psalm.xml index 8fe31fae7a9..46d39f56301 100644 --- a/psalm.xml +++ b/psalm.xml @@ -160,6 +160,7 @@ + @@ -258,6 +259,7 @@ + diff --git a/src/Persisters/Entity/BasicEntityPersister.php b/src/Persisters/Entity/BasicEntityPersister.php index 0d11dc9238d..e83589c4180 100644 --- a/src/Persisters/Entity/BasicEntityPersister.php +++ b/src/Persisters/Entity/BasicEntityPersister.php @@ -31,6 +31,7 @@ use Doctrine\ORM\Repository\Exception\InvalidFindByCall; use Doctrine\ORM\UnitOfWork; use Doctrine\ORM\Utility\IdentifierFlattener; +use Doctrine\ORM\Utility\LockSqlHelper; use Doctrine\ORM\Utility\PersisterHelper; use LengthException; @@ -92,6 +93,8 @@ */ class BasicEntityPersister implements EntityPersister { + use LockSqlHelper; + /** @var array */ private static $comparisonMap = [ Comparison::EQ => '= %s', @@ -1116,11 +1119,11 @@ public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit switch ($lockMode) { case LockMode::PESSIMISTIC_READ: - $lockSql = ' ' . $this->platform->getReadLockSQL(); + $lockSql = ' ' . $this->getReadLockSQL($this->platform); break; case LockMode::PESSIMISTIC_WRITE: - $lockSql = ' ' . $this->platform->getWriteLockSQL(); + $lockSql = ' ' . $this->getWriteLockSQL($this->platform); break; } @@ -1578,11 +1581,11 @@ public function lock(array $criteria, $lockMode) switch ($lockMode) { case LockMode::PESSIMISTIC_READ: - $lockSql = $this->platform->getReadLockSQL(); + $lockSql = $this->getReadLockSQL($this->platform); break; case LockMode::PESSIMISTIC_WRITE: - $lockSql = $this->platform->getWriteLockSQL(); + $lockSql = $this->getWriteLockSQL($this->platform); break; } diff --git a/src/Persisters/Entity/JoinedSubclassPersister.php b/src/Persisters/Entity/JoinedSubclassPersister.php index f286ac1d8e4..1d6a47855f9 100644 --- a/src/Persisters/Entity/JoinedSubclassPersister.php +++ b/src/Persisters/Entity/JoinedSubclassPersister.php @@ -10,6 +10,7 @@ use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Internal\SQLResultCasing; use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Utility\LockSqlHelper; use Doctrine\ORM\Utility\PersisterHelper; use LengthException; @@ -26,6 +27,7 @@ */ class JoinedSubclassPersister extends AbstractEntityInheritancePersister { + use LockSqlHelper; use SQLResultCasing; /** @@ -316,12 +318,12 @@ public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit switch ($lockMode) { case LockMode::PESSIMISTIC_READ: - $lockSql = ' ' . $this->platform->getReadLockSQL(); + $lockSql = ' ' . $this->getReadLockSQL($this->platform); break; case LockMode::PESSIMISTIC_WRITE: - $lockSql = ' ' . $this->platform->getWriteLockSQL(); + $lockSql = ' ' . $this->getWriteLockSQL($this->platform); break; } diff --git a/src/Query/SqlWalker.php b/src/Query/SqlWalker.php index 34e5b22580d..f3d0ab794c0 100644 --- a/src/Query/SqlWalker.php +++ b/src/Query/SqlWalker.php @@ -16,6 +16,7 @@ use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\Query; use Doctrine\ORM\Utility\HierarchyDiscriminatorResolver; +use Doctrine\ORM\Utility\LockSqlHelper; use Doctrine\ORM\Utility\PersisterHelper; use InvalidArgumentException; use LogicException; @@ -48,6 +49,8 @@ */ class SqlWalker implements TreeWalker { + use LockSqlHelper; + public const HINT_DISTINCT = 'doctrine.distinct'; /** @@ -577,11 +580,11 @@ public function walkSelectStatement(AST\SelectStatement $AST) } if ($lockMode === LockMode::PESSIMISTIC_READ) { - return $sql . ' ' . $this->platform->getReadLockSQL(); + return $sql . ' ' . $this->getReadLockSQL($this->platform); } if ($lockMode === LockMode::PESSIMISTIC_WRITE) { - return $sql . ' ' . $this->platform->getWriteLockSQL(); + return $sql . ' ' . $this->getWriteLockSQL($this->platform); } if ($lockMode !== LockMode::OPTIMISTIC) { diff --git a/src/Utility/LockSqlHelper.php b/src/Utility/LockSqlHelper.php new file mode 100644 index 00000000000..30d86a5ce5c --- /dev/null +++ b/src/Utility/LockSqlHelper.php @@ -0,0 +1,47 @@ +getWriteLockSQL($platform); + } + + private function getWriteLockSQL(AbstractPlatform $platform): string + { + if ($platform instanceof DB2Platform) { + return 'WITH RR USE AND KEEP UPDATE LOCKS'; + } + + if ($platform instanceof SqlitePlatform) { + return ''; + } + + if ($platform instanceof SQLServerPlatform) { + return ''; + } + + return 'FOR UPDATE'; + } +} diff --git a/tests/Tests/ORM/Functional/Locking/LockTest.php b/tests/Tests/ORM/Functional/Locking/LockTest.php index c3992212748..2b5b398ce8d 100644 --- a/tests/Tests/ORM/Functional/Locking/LockTest.php +++ b/tests/Tests/ORM/Functional/Locking/LockTest.php @@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Functional\Locking; use Doctrine\DBAL\LockMode; +use Doctrine\DBAL\Platforms\SQLitePlatform; use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\Query; use Doctrine\ORM\TransactionRequiredException; @@ -168,9 +169,7 @@ public function testRefreshWithLockPessimisticWriteNoTransactionThrowsException( */ public function testLockPessimisticWrite(): void { - $writeLockSql = $this->_em->getConnection()->getDatabasePlatform()->getWriteLockSQL(); - - if (! $writeLockSql) { + if ($this->_em->getConnection()->getDatabasePlatform() instanceof SQLitePlatform) { self::markTestSkipped('Database Driver has no Write Lock support.'); } @@ -195,7 +194,7 @@ public function testLockPessimisticWrite(): void $lastLoggedQuery = $this->getLastLoggedQuery(1)['sql']; } - self::assertStringContainsString($writeLockSql, $lastLoggedQuery); + self::assertStringContainsString('FOR UPDATE', $lastLoggedQuery); } /** @@ -203,9 +202,7 @@ public function testLockPessimisticWrite(): void */ public function testRefreshWithLockPessimisticWrite(): void { - $writeLockSql = $this->_em->getConnection()->getDatabasePlatform()->getWriteLockSQL(); - - if (! $writeLockSql) { + if ($this->_em->getConnection()->getDatabasePlatform() instanceof SQLitePlatform) { self::markTestSkipped('Database Driver has no Write Lock support.'); } @@ -230,15 +227,13 @@ public function testRefreshWithLockPessimisticWrite(): void $lastLoggedQuery = $this->getLastLoggedQuery(1)['sql']; } - self::assertStringContainsString($writeLockSql, $lastLoggedQuery); + self::assertStringContainsString('FOR UPDATE', $lastLoggedQuery); } /** @group DDC-178 */ public function testLockPessimisticRead(): void { - $readLockSql = $this->_em->getConnection()->getDatabasePlatform()->getReadLockSQL(); - - if (! $readLockSql) { + if ($this->_em->getConnection()->getDatabasePlatform() instanceof SQLitePlatform) { self::markTestSkipped('Database Driver has no Write Lock support.'); } @@ -264,7 +259,11 @@ public function testLockPessimisticRead(): void $lastLoggedQuery = $this->getLastLoggedQuery(1)['sql']; } - self::assertStringContainsString($readLockSql, $lastLoggedQuery); + self::assertThat($lastLoggedQuery, self::logicalOr( + self::stringContains('FOR UPDATE'), + self::stringContains('FOR SHARE'), + self::stringContains('LOCK IN SHARE MODE') + )); } /** @group DDC-1693 */ diff --git a/tests/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php b/tests/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php index e3863300412..cb69a3a5674 100644 --- a/tests/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php +++ b/tests/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php @@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Tools\Pagination; +use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Platforms\OraclePlatform; use Doctrine\DBAL\Platforms\PostgreSQLPlatform; @@ -18,273 +19,212 @@ class_exists('Doctrine\DBAL\Platforms\PostgreSqlPlatform'); final class LimitSubqueryOutputWalkerTest extends PaginationTestCase { + /** + * @var AbstractPlatform|null + */ + private $originalDatabasePlatform; + + protected function setUp(): void + { + parent::setUp(); + + $this->originalDatabasePlatform = $this->entityManager->getConnection()->getDatabasePlatform(); + } + + protected function tearDown(): void + { + if ($this->originalDatabasePlatform) { + $this->entityManager->getConnection()->setDatabasePlatform($this->originalDatabasePlatform); + } + + parent::tearDown(); + } + + private function replaceDatabasePlatform(AbstractPlatform $platform): void + { + $this->entityManager->getConnection()->setDatabasePlatform($platform); + } + public function testLimitSubquery(): void { - $query = $this->entityManager->createQuery( - 'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a' - ); - $query->expireQueryCache(true); - $limitQuery = clone $query; - $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a'); self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT m0_.id AS id_0, m0_.title AS title_1, c1_.id AS id_2, a2_.id AS id_3, a2_.name AS name_4, m0_.author_id AS author_id_5, m0_.category_id AS category_id_6 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result', - $limitQuery->getSQL() + 'SELECT DISTINCT id_0 FROM (SELECT m0_.id AS id_0, m0_.title AS title_1, c1_.id AS id_2, a2_.id AS id_3, a2_.name AS name_4, m0_.author_id AS author_id_5, m0_.category_id AS category_id_6 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result LIMIT 20 OFFSET 10', + $query->getSQL() ); } public function testLimitSubqueryWithSortPg(): void { - $odp = $this->entityManager->getConnection()->getDatabasePlatform(); - $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSQLPlatform()); + $this->replaceDatabasePlatform(new PostgreSQLPlatform()); - $query = $this->entityManager->createQuery( - 'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a ORDER BY p.title' - ); - $limitQuery = clone $query; - $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a ORDER BY p.title'); self::assertSame( - 'SELECT DISTINCT id_0, MIN(sclr_5) AS dctrn_minrownum FROM (SELECT m0_.id AS id_0, m0_.title AS title_1, c1_.id AS id_2, a2_.id AS id_3, a2_.name AS name_4, ROW_NUMBER() OVER(ORDER BY m0_.title ASC) AS sclr_5, m0_.author_id AS author_id_6, m0_.category_id AS category_id_7 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', - $limitQuery->getSQL() + 'SELECT DISTINCT id_0, MIN(sclr_5) AS dctrn_minrownum FROM (SELECT m0_.id AS id_0, m0_.title AS title_1, c1_.id AS id_2, a2_.id AS id_3, a2_.name AS name_4, ROW_NUMBER() OVER(ORDER BY m0_.title ASC) AS sclr_5, m0_.author_id AS author_id_6, m0_.category_id AS category_id_7 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC LIMIT 20 OFFSET 10', + $query->getSQL() ); - - $this->entityManager->getConnection()->setDatabasePlatform($odp); } public function testLimitSubqueryWithScalarSortPg(): void { - $odp = $this->entityManager->getConnection()->getDatabasePlatform(); - $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSQLPlatform()); + $this->replaceDatabasePlatform(new PostgreSQLPlatform()); - $query = $this->entityManager->createQuery( - 'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity' - ); - $limitQuery = clone $query; - $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity'); self::assertSame( - 'SELECT DISTINCT id_1, MIN(sclr_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS sclr_0, u1_.id AS id_1, g0_.id AS id_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC) AS sclr_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY id_1 ORDER BY dctrn_minrownum ASC', - $limitQuery->getSQL() + 'SELECT DISTINCT id_1, MIN(sclr_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS sclr_0, u1_.id AS id_1, g0_.id AS id_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC) AS sclr_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY id_1 ORDER BY dctrn_minrownum ASC LIMIT 20 OFFSET 10', + $query->getSQL() ); - - $this->entityManager->getConnection()->setDatabasePlatform($odp); } public function testLimitSubqueryWithMixedSortPg(): void { - $odp = $this->entityManager->getConnection()->getDatabasePlatform(); - $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSQLPlatform()); + $this->replaceDatabasePlatform(new PostgreSQLPlatform()); - $query = $this->entityManager->createQuery( - 'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC' - ); - $limitQuery = clone $query; - $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC'); self::assertSame( - 'SELECT DISTINCT id_1, MIN(sclr_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS sclr_0, u1_.id AS id_1, g0_.id AS id_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC, u1_.id DESC) AS sclr_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY id_1 ORDER BY dctrn_minrownum ASC', - $limitQuery->getSQL() + 'SELECT DISTINCT id_1, MIN(sclr_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS sclr_0, u1_.id AS id_1, g0_.id AS id_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC, u1_.id DESC) AS sclr_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY id_1 ORDER BY dctrn_minrownum ASC LIMIT 20 OFFSET 10', + $query->getSQL() ); - - $this->entityManager->getConnection()->setDatabasePlatform($odp); } public function testLimitSubqueryWithHiddenScalarSortPg(): void { - $odp = $this->entityManager->getConnection()->getDatabasePlatform(); - $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSQLPlatform()); + $this->replaceDatabasePlatform(new PostgreSQLPlatform()); - $query = $this->entityManager->createQuery( - 'SELECT u, g, COUNT(g.id) AS hidden g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC' - ); - $limitQuery = clone $query; - $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT u, g, COUNT(g.id) AS hidden g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC'); self::assertSame( - 'SELECT DISTINCT id_1, MIN(sclr_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS sclr_0, u1_.id AS id_1, g0_.id AS id_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC, u1_.id DESC) AS sclr_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY id_1 ORDER BY dctrn_minrownum ASC', - $limitQuery->getSQL() + 'SELECT DISTINCT id_1, MIN(sclr_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS sclr_0, u1_.id AS id_1, g0_.id AS id_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC, u1_.id DESC) AS sclr_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY id_1 ORDER BY dctrn_minrownum ASC LIMIT 20 OFFSET 10', + $query->getSQL() ); - - $this->entityManager->getConnection()->setDatabasePlatform($odp); } public function testLimitSubqueryPg(): void { - $odp = $this->entityManager->getConnection()->getDatabasePlatform(); - $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSQLPlatform()); + $this->replaceDatabasePlatform(new PostgreSQLPlatform()); $this->testLimitSubquery(); - - $this->entityManager->getConnection()->setDatabasePlatform($odp); } public function testLimitSubqueryWithSortOracle(): void { - $odp = $this->entityManager->getConnection()->getDatabasePlatform(); - $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform()); + $this->replaceDatabasePlatform(new OraclePlatform()); - $query = $this->entityManager->createQuery( - 'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a ORDER BY p.title' - ); - $query->expireQueryCache(true); - $limitQuery = clone $query; - $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a ORDER BY p.title'); self::assertSame( - 'SELECT DISTINCT ID_0, MIN(SCLR_5) AS dctrn_minrownum FROM (SELECT m0_.id AS ID_0, m0_.title AS TITLE_1, c1_.id AS ID_2, a2_.id AS ID_3, a2_.name AS NAME_4, ROW_NUMBER() OVER(ORDER BY m0_.title ASC) AS SCLR_5, m0_.author_id AS AUTHOR_ID_6, m0_.category_id AS CATEGORY_ID_7 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result GROUP BY ID_0 ORDER BY dctrn_minrownum ASC', - $limitQuery->getSQL() + 'SELECT * FROM (SELECT a.*, ROWNUM AS doctrine_rownum FROM (SELECT DISTINCT ID_0, MIN(SCLR_5) AS dctrn_minrownum FROM (SELECT m0_.id AS ID_0, m0_.title AS TITLE_1, c1_.id AS ID_2, a2_.id AS ID_3, a2_.name AS NAME_4, ROW_NUMBER() OVER(ORDER BY m0_.title ASC) AS SCLR_5, m0_.author_id AS AUTHOR_ID_6, m0_.category_id AS CATEGORY_ID_7 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result GROUP BY ID_0 ORDER BY dctrn_minrownum ASC) a WHERE ROWNUM <= 30) WHERE doctrine_rownum >= 11', + $query->getSQL() ); - - $this->entityManager->getConnection()->setDatabasePlatform($odp); } public function testLimitSubqueryWithScalarSortOracle(): void { - $odp = $this->entityManager->getConnection()->getDatabasePlatform(); - $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform()); + $this->replaceDatabasePlatform(new OraclePlatform()); - $query = $this->entityManager->createQuery( - 'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity' - ); - $query->expireQueryCache(true); - $limitQuery = clone $query; - $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity'); self::assertSame( - 'SELECT DISTINCT ID_1, MIN(SCLR_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS SCLR_0, u1_.id AS ID_1, g0_.id AS ID_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC) AS SCLR_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY ID_1 ORDER BY dctrn_minrownum ASC', - $limitQuery->getSQL() + 'SELECT * FROM (SELECT a.*, ROWNUM AS doctrine_rownum FROM (SELECT DISTINCT ID_1, MIN(SCLR_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS SCLR_0, u1_.id AS ID_1, g0_.id AS ID_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC) AS SCLR_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY ID_1 ORDER BY dctrn_minrownum ASC) a WHERE ROWNUM <= 30) WHERE doctrine_rownum >= 11', + $query->getSQL() ); - - $this->entityManager->getConnection()->setDatabasePlatform($odp); } public function testLimitSubqueryWithMixedSortOracle(): void { - $odp = $this->entityManager->getConnection()->getDatabasePlatform(); - $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform()); + $this->replaceDatabasePlatform(new OraclePlatform()); - $query = $this->entityManager->createQuery( - 'SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC' - ); - $query->expireQueryCache(true); - $limitQuery = clone $query; - $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT u, g, COUNT(g.id) AS g_quantity FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g ORDER BY g_quantity, u.id DESC'); self::assertSame( - 'SELECT DISTINCT ID_1, MIN(SCLR_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS SCLR_0, u1_.id AS ID_1, g0_.id AS ID_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC, u1_.id DESC) AS SCLR_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY ID_1 ORDER BY dctrn_minrownum ASC', - $limitQuery->getSQL() + 'SELECT * FROM (SELECT a.*, ROWNUM AS doctrine_rownum FROM (SELECT DISTINCT ID_1, MIN(SCLR_3) AS dctrn_minrownum FROM (SELECT COUNT(g0_.id) AS SCLR_0, u1_.id AS ID_1, g0_.id AS ID_2, ROW_NUMBER() OVER(ORDER BY COUNT(g0_.id) ASC, u1_.id DESC) AS SCLR_3 FROM User u1_ INNER JOIN user_group u2_ ON u1_.id = u2_.user_id INNER JOIN groups g0_ ON g0_.id = u2_.group_id) dctrn_result GROUP BY ID_1 ORDER BY dctrn_minrownum ASC) a WHERE ROWNUM <= 30) WHERE doctrine_rownum >= 11', + $query->getSQL() ); - - $this->entityManager->getConnection()->setDatabasePlatform($odp); } public function testLimitSubqueryOracle(): void { - $odp = $this->entityManager->getConnection()->getDatabasePlatform(); - $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform()); + $this->replaceDatabasePlatform(new OraclePlatform()); - $query = $this->entityManager->createQuery( - 'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a' - ); - $query->expireQueryCache(true); - $limitQuery = clone $query; - $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a'); self::assertSame( - 'SELECT DISTINCT ID_0 FROM (SELECT m0_.id AS ID_0, m0_.title AS TITLE_1, c1_.id AS ID_2, a2_.id AS ID_3, a2_.name AS NAME_4, m0_.author_id AS AUTHOR_ID_5, m0_.category_id AS CATEGORY_ID_6 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result', - $limitQuery->getSQL() + 'SELECT * FROM (SELECT a.*, ROWNUM AS doctrine_rownum FROM (SELECT DISTINCT ID_0 FROM (SELECT m0_.id AS ID_0, m0_.title AS TITLE_1, c1_.id AS ID_2, a2_.id AS ID_3, a2_.name AS NAME_4, m0_.author_id AS AUTHOR_ID_5, m0_.category_id AS CATEGORY_ID_6 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result) a WHERE ROWNUM <= 30) WHERE doctrine_rownum >= 11', + $query->getSQL() ); - - $this->entityManager->getConnection()->setDatabasePlatform($odp); } public function testCountQueryMixedResultsWithName(): void { - $query = $this->entityManager->createQuery( - 'SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a' - ); - $limitQuery = clone $query; - $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a'); self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, sum(a0_.name) AS sclr_2 FROM Author a0_) dctrn_result', - $limitQuery->getSQL() + 'SELECT DISTINCT id_0 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, sum(a0_.name) AS sclr_2 FROM Author a0_) dctrn_result LIMIT 20 OFFSET 10', + $query->getSQL() ); } /** @group DDC-3336 */ public function testCountQueryWithArithmeticOrderByCondition(): void { - $query = $this->entityManager->createQuery( - 'SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Author a ORDER BY (1 - 1000) * 1 DESC' - ); - $this->entityManager->getConnection()->setDatabasePlatform(new MySQLPlatform()); + $this->replaceDatabasePlatform(new MySQLPlatform()); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Author a ORDER BY (1 - 1000) * 1 DESC'); self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, (1 - 1000) * 1 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1 FROM Author a0_) dctrn_result_inner ORDER BY (1 - 1000) * 1 DESC) dctrn_result', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, (1 - 1000) * 1 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1 FROM Author a0_) dctrn_result_inner ORDER BY (1 - 1000) * 1 DESC) dctrn_result LIMIT 20 OFFSET 10', $query->getSQL() ); } public function testCountQueryWithComplexScalarOrderByItemWithoutJoin(): void { - $query = $this->entityManager->createQuery( - 'SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Avatar a ORDER BY a.imageHeight * a.imageWidth DESC' - ); - $this->entityManager->getConnection()->setDatabasePlatform(new MySQLPlatform()); + $this->replaceDatabasePlatform(new MySQLPlatform()); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Avatar a ORDER BY a.imageHeight * a.imageWidth DESC'); self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, imageHeight_2 * imageWidth_3 FROM (SELECT a0_.id AS id_0, a0_.image AS image_1, a0_.imageHeight AS imageHeight_2, a0_.imageWidth AS imageWidth_3, a0_.imageAltDesc AS imageAltDesc_4, a0_.user_id AS user_id_5 FROM Avatar a0_) dctrn_result_inner ORDER BY imageHeight_2 * imageWidth_3 DESC) dctrn_result', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, imageHeight_2 * imageWidth_3 FROM (SELECT a0_.id AS id_0, a0_.image AS image_1, a0_.imageHeight AS imageHeight_2, a0_.imageWidth AS imageWidth_3, a0_.imageAltDesc AS imageAltDesc_4, a0_.user_id AS user_id_5 FROM Avatar a0_) dctrn_result_inner ORDER BY imageHeight_2 * imageWidth_3 DESC) dctrn_result LIMIT 20 OFFSET 10', $query->getSQL() ); } public function testCountQueryWithComplexScalarOrderByItemJoinedWithoutPartial(): void { - $query = $this->entityManager->createQuery( - 'SELECT u FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.avatar a ORDER BY a.imageHeight * a.imageWidth DESC' - ); - $this->entityManager->getConnection()->setDatabasePlatform(new MySQLPlatform()); + $this->replaceDatabasePlatform(new MySQLPlatform()); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT u FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.avatar a ORDER BY a.imageHeight * a.imageWidth DESC'); self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, imageHeight_3 * imageWidth_4 FROM (SELECT u0_.id AS id_0, a1_.id AS id_1, a1_.image AS image_2, a1_.imageHeight AS imageHeight_3, a1_.imageWidth AS imageWidth_4, a1_.imageAltDesc AS imageAltDesc_5, a1_.user_id AS user_id_6 FROM User u0_ INNER JOIN Avatar a1_ ON u0_.id = a1_.user_id) dctrn_result_inner ORDER BY imageHeight_3 * imageWidth_4 DESC) dctrn_result', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, imageHeight_3 * imageWidth_4 FROM (SELECT u0_.id AS id_0, a1_.id AS id_1, a1_.image AS image_2, a1_.imageHeight AS imageHeight_3, a1_.imageWidth AS imageWidth_4, a1_.imageAltDesc AS imageAltDesc_5, a1_.user_id AS user_id_6 FROM User u0_ INNER JOIN Avatar a1_ ON u0_.id = a1_.user_id) dctrn_result_inner ORDER BY imageHeight_3 * imageWidth_4 DESC) dctrn_result LIMIT 20 OFFSET 10', $query->getSQL() ); } public function testCountQueryWithComplexScalarOrderByItemJoinedWithPartial(): void { - $query = $this->entityManager->createQuery( - 'SELECT u, partial a.{id, imageAltDesc} FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.avatar a ORDER BY a.imageHeight * a.imageWidth DESC' - ); - $this->entityManager->getConnection()->setDatabasePlatform(new MySQLPlatform()); + $this->replaceDatabasePlatform(new MySQLPlatform()); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT u, partial a.{id, imageAltDesc} FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.avatar a ORDER BY a.imageHeight * a.imageWidth DESC'); self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, imageHeight_5 * imageWidth_6 FROM (SELECT u0_.id AS id_0, a1_.id AS id_1, a1_.imageAltDesc AS imageAltDesc_2, a1_.id AS id_3, a1_.image AS image_4, a1_.imageHeight AS imageHeight_5, a1_.imageWidth AS imageWidth_6, a1_.imageAltDesc AS imageAltDesc_7, a1_.user_id AS user_id_8 FROM User u0_ INNER JOIN Avatar a1_ ON u0_.id = a1_.user_id) dctrn_result_inner ORDER BY imageHeight_5 * imageWidth_6 DESC) dctrn_result', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, imageHeight_5 * imageWidth_6 FROM (SELECT u0_.id AS id_0, a1_.id AS id_1, a1_.imageAltDesc AS imageAltDesc_2, a1_.id AS id_3, a1_.image AS image_4, a1_.imageHeight AS imageHeight_5, a1_.imageWidth AS imageWidth_6, a1_.imageAltDesc AS imageAltDesc_7, a1_.user_id AS user_id_8 FROM User u0_ INNER JOIN Avatar a1_ ON u0_.id = a1_.user_id) dctrn_result_inner ORDER BY imageHeight_5 * imageWidth_6 DESC) dctrn_result LIMIT 20 OFFSET 10', $query->getSQL() ); } public function testCountQueryWithComplexScalarOrderByItemOracle(): void { - $query = $this->entityManager->createQuery( - 'SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Avatar a ORDER BY a.imageHeight * a.imageWidth DESC' - ); - $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform()); + $this->replaceDatabasePlatform(new OraclePlatform()); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Avatar a ORDER BY a.imageHeight * a.imageWidth DESC'); self::assertSame( - 'SELECT DISTINCT ID_0, MIN(SCLR_5) AS dctrn_minrownum FROM (SELECT a0_.id AS ID_0, a0_.image AS IMAGE_1, a0_.imageHeight AS IMAGEHEIGHT_2, a0_.imageWidth AS IMAGEWIDTH_3, a0_.imageAltDesc AS IMAGEALTDESC_4, ROW_NUMBER() OVER(ORDER BY a0_.imageHeight * a0_.imageWidth DESC) AS SCLR_5, a0_.user_id AS USER_ID_6 FROM Avatar a0_) dctrn_result GROUP BY ID_0 ORDER BY dctrn_minrownum ASC', + 'SELECT * FROM (SELECT a.*, ROWNUM AS doctrine_rownum FROM (SELECT DISTINCT ID_0, MIN(SCLR_5) AS dctrn_minrownum FROM (SELECT a0_.id AS ID_0, a0_.image AS IMAGE_1, a0_.imageHeight AS IMAGEHEIGHT_2, a0_.imageWidth AS IMAGEWIDTH_3, a0_.imageAltDesc AS IMAGEALTDESC_4, ROW_NUMBER() OVER(ORDER BY a0_.imageHeight * a0_.imageWidth DESC) AS SCLR_5, a0_.user_id AS USER_ID_6 FROM Avatar a0_) dctrn_result GROUP BY ID_0 ORDER BY dctrn_minrownum ASC) a WHERE ROWNUM <= 30) WHERE doctrine_rownum >= 11', $query->getSQL() ); } @@ -292,75 +232,65 @@ public function testCountQueryWithComplexScalarOrderByItemOracle(): void /** @group DDC-3434 */ public function testLimitSubqueryWithHiddenSelectionInOrderBy(): void { - $query = $this->entityManager->createQuery( + $query = $this->createQuery( 'SELECT a, a.name AS HIDDEN ord FROM Doctrine\Tests\ORM\Tools\Pagination\Author a ORDER BY ord DESC' ); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); - self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, name_2 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, a0_.name AS name_2 FROM Author a0_) dctrn_result_inner ORDER BY name_2 DESC) dctrn_result', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, name_2 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, a0_.name AS name_2 FROM Author a0_) dctrn_result_inner ORDER BY name_2 DESC) dctrn_result LIMIT 20 OFFSET 10', $query->getSQL() ); } public function testLimitSubqueryWithColumnWithSortDirectionInName(): void { - $query = $this->entityManager->createQuery( - 'SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Avatar a ORDER BY a.imageAltDesc DESC' - ); - $this->entityManager->getConnection()->setDatabasePlatform(new MySQLPlatform()); - - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $this->replaceDatabasePlatform(new MySQLPlatform()); + $query = $this->createQuery('SELECT a FROM Doctrine\Tests\ORM\Tools\Pagination\Avatar a ORDER BY a.imageAltDesc DESC'); self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, imageAltDesc_4 FROM (SELECT a0_.id AS id_0, a0_.image AS image_1, a0_.imageHeight AS imageHeight_2, a0_.imageWidth AS imageWidth_3, a0_.imageAltDesc AS imageAltDesc_4, a0_.user_id AS user_id_5 FROM Avatar a0_) dctrn_result_inner ORDER BY imageAltDesc_4 DESC) dctrn_result', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, imageAltDesc_4 FROM (SELECT a0_.id AS id_0, a0_.image AS image_1, a0_.imageHeight AS imageHeight_2, a0_.imageWidth AS imageWidth_3, a0_.imageAltDesc AS imageAltDesc_4, a0_.user_id AS user_id_5 FROM Avatar a0_) dctrn_result_inner ORDER BY imageAltDesc_4 DESC) dctrn_result LIMIT 20 OFFSET 10', $query->getSQL() ); } public function testLimitSubqueryWithOrderByInnerJoined(): void { - $query = $this->entityManager->createQuery( - 'SELECT b FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost b JOIN b.author a ORDER BY a.name ASC' - ); - - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query = $this->createQuery('SELECT b FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost b JOIN b.author a ORDER BY a.name ASC'); self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, name_2 FROM (SELECT b0_.id AS id_0, a1_.id AS id_1, a1_.name AS name_2, b0_.author_id AS author_id_3, b0_.category_id AS category_id_4 FROM BlogPost b0_ INNER JOIN Author a1_ ON b0_.author_id = a1_.id) dctrn_result_inner ORDER BY name_2 ASC) dctrn_result', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, name_2 FROM (SELECT b0_.id AS id_0, a1_.id AS id_1, a1_.name AS name_2, b0_.author_id AS author_id_3, b0_.category_id AS category_id_4 FROM BlogPost b0_ INNER JOIN Author a1_ ON b0_.author_id = a1_.id) dctrn_result_inner ORDER BY name_2 ASC) dctrn_result LIMIT 20 OFFSET 10', $query->getSQL() ); } public function testLimitSubqueryWithOrderByAndSubSelectInWhereClauseMySql(): void { - $this->entityManager->getConnection()->setDatabasePlatform(new MySQLPlatform()); - $query = $this->entityManager->createQuery( + $this->replaceDatabasePlatform(new MySQLPlatform()); + + $query = $this->createQuery( 'SELECT b FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost b WHERE ((SELECT COUNT(simple.id) FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost simple) = 1) ORDER BY b.id DESC' ); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0 FROM (SELECT b0_.id AS id_0, b0_.author_id AS author_id_1, b0_.category_id AS category_id_2 FROM BlogPost b0_ WHERE ((SELECT COUNT(b1_.id) AS sclr_3 FROM BlogPost b1_) = 1)) dctrn_result_inner ORDER BY id_0 DESC) dctrn_result', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0 FROM (SELECT b0_.id AS id_0, b0_.author_id AS author_id_1, b0_.category_id AS category_id_2 FROM BlogPost b0_ WHERE ((SELECT COUNT(b1_.id) AS sclr_3 FROM BlogPost b1_) = 1)) dctrn_result_inner ORDER BY id_0 DESC) dctrn_result LIMIT 20 OFFSET 10', $query->getSQL() ); } public function testLimitSubqueryWithOrderByAndSubSelectInWhereClausePgSql(): void { - $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSQLPlatform()); - $query = $this->entityManager->createQuery( + $this->replaceDatabasePlatform(new PostgreSQLPlatform()); + + $query = $this->createQuery( 'SELECT b FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost b WHERE ((SELECT COUNT(simple.id) FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost simple) = 1) ORDER BY b.id DESC' ); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); self::assertSame( - 'SELECT DISTINCT id_0, MIN(sclr_1) AS dctrn_minrownum FROM (SELECT b0_.id AS id_0, ROW_NUMBER() OVER(ORDER BY b0_.id DESC) AS sclr_1, b0_.author_id AS author_id_2, b0_.category_id AS category_id_3 FROM BlogPost b0_ WHERE ((SELECT COUNT(b1_.id) AS sclr_4 FROM BlogPost b1_) = 1)) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', + 'SELECT DISTINCT id_0, MIN(sclr_1) AS dctrn_minrownum FROM (SELECT b0_.id AS id_0, ROW_NUMBER() OVER(ORDER BY b0_.id DESC) AS sclr_1, b0_.author_id AS author_id_2, b0_.category_id AS category_id_3 FROM BlogPost b0_ WHERE ((SELECT COUNT(b1_.id) AS sclr_4 FROM BlogPost b1_) = 1)) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC LIMIT 20 OFFSET 10', $query->getSQL() ); } @@ -370,16 +300,15 @@ public function testLimitSubqueryWithOrderByAndSubSelectInWhereClausePgSql(): vo */ public function testLimitSubqueryOrderByFieldFromMappedSuperclass(): void { - $this->entityManager->getConnection()->setDatabasePlatform(new MySQLPlatform()); + $this->replaceDatabasePlatform(new MySQLPlatform()); // now use the third one in query - $query = $this->entityManager->createQuery( + $query = $this->createQuery( 'SELECT b FROM Doctrine\Tests\ORM\Tools\Pagination\Banner b ORDER BY b.id DESC' ); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0 FROM (SELECT b0_.id AS id_0, b0_.name AS name_1 FROM Banner b0_) dctrn_result_inner ORDER BY id_0 DESC) dctrn_result', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0 FROM (SELECT b0_.id AS id_0, b0_.name AS name_1 FROM Banner b0_) dctrn_result_inner ORDER BY id_0 DESC) dctrn_result LIMIT 20 OFFSET 10', $query->getSQL() ); } @@ -389,9 +318,9 @@ public function testLimitSubqueryOrderByFieldFromMappedSuperclass(): void */ public function testLimitSubqueryOrderBySubSelectOrderByExpression(): void { - $this->entityManager->getConnection()->setDatabasePlatform(new MySQLPlatform()); + $this->replaceDatabasePlatform(new MySQLPlatform()); - $query = $this->entityManager->createQuery( + $query = $this->createQuery( 'SELECT a, ( SELECT MIN(bp.title) @@ -401,10 +330,9 @@ public function testLimitSubqueryOrderBySubSelectOrderByExpression(): void FROM Doctrine\Tests\ORM\Tools\Pagination\Author a ORDER BY first_blog_post DESC' ); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); self::assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, sclr_2 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS sclr_3 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2 FROM Author a0_) dctrn_result_inner ORDER BY sclr_2 DESC) dctrn_result', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, sclr_2 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS sclr_3 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2 FROM Author a0_) dctrn_result_inner ORDER BY sclr_2 DESC) dctrn_result LIMIT 20 OFFSET 10', $query->getSQL() ); } @@ -414,9 +342,9 @@ public function testLimitSubqueryOrderBySubSelectOrderByExpression(): void */ public function testLimitSubqueryOrderBySubSelectOrderByExpressionPg(): void { - $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSQLPlatform()); + $this->replaceDatabasePlatform(new PostgreSQLPlatform()); - $query = $this->entityManager->createQuery( + $query = $this->createQuery( 'SELECT a, ( SELECT MIN(bp.title) @@ -426,10 +354,9 @@ public function testLimitSubqueryOrderBySubSelectOrderByExpressionPg(): void FROM Doctrine\Tests\ORM\Tools\Pagination\Author a ORDER BY first_blog_post DESC' ); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); self::assertSame( - 'SELECT DISTINCT id_0, MIN(sclr_4) AS dctrn_minrownum FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS sclr_3 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2, ROW_NUMBER() OVER(ORDER BY (SELECT MIN(m1_.title) AS sclr_5 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) DESC) AS sclr_4 FROM Author a0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', + 'SELECT DISTINCT id_0, MIN(sclr_4) AS dctrn_minrownum FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS sclr_3 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2, ROW_NUMBER() OVER(ORDER BY (SELECT MIN(m1_.title) AS sclr_5 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) DESC) AS sclr_4 FROM Author a0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC LIMIT 20 OFFSET 10', $query->getSQL() ); } @@ -439,9 +366,9 @@ public function testLimitSubqueryOrderBySubSelectOrderByExpressionPg(): void */ public function testLimitSubqueryOrderBySubSelectOrderByExpressionOracle(): void { - $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform()); + $this->replaceDatabasePlatform(new OraclePlatform()); - $query = $this->entityManager->createQuery( + $query = $this->createQuery( 'SELECT a, ( SELECT MIN(bp.title) @@ -451,11 +378,20 @@ public function testLimitSubqueryOrderBySubSelectOrderByExpressionOracle(): void FROM Doctrine\Tests\ORM\Tools\Pagination\Author a ORDER BY first_blog_post DESC' ); - $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); self::assertSame( - 'SELECT DISTINCT ID_0, MIN(SCLR_4) AS dctrn_minrownum FROM (SELECT a0_.id AS ID_0, a0_.name AS NAME_1, (SELECT MIN(m1_.title) AS SCLR_3 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS SCLR_2, ROW_NUMBER() OVER(ORDER BY (SELECT MIN(m1_.title) AS SCLR_5 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) DESC) AS SCLR_4 FROM Author a0_) dctrn_result GROUP BY ID_0 ORDER BY dctrn_minrownum ASC', + 'SELECT * FROM (SELECT a.*, ROWNUM AS doctrine_rownum FROM (SELECT DISTINCT ID_0, MIN(SCLR_4) AS dctrn_minrownum FROM (SELECT a0_.id AS ID_0, a0_.name AS NAME_1, (SELECT MIN(m1_.title) AS SCLR_3 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS SCLR_2, ROW_NUMBER() OVER(ORDER BY (SELECT MIN(m1_.title) AS SCLR_5 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) DESC) AS SCLR_4 FROM Author a0_) dctrn_result GROUP BY ID_0 ORDER BY dctrn_minrownum ASC) a WHERE ROWNUM <= 30) WHERE doctrine_rownum >= 11', $query->getSQL() ); } + + private function createQuery(string $dql): Query + { + $query = $this->entityManager->createQuery($dql); + $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); + $query->setFirstResult(10); + $query->setMaxResults(20); + + return $query; + } }