1
0
mirror of synced 2025-03-06 21:06:16 +03:00

Merge pull request #6500 from SamKnows/feature/override-aggregate-functions

Allow internal functions to be overridden.
This commit is contained in:
Marco Pivetta 2017-06-20 07:29:51 +02:00 committed by GitHub
commit 256091282e
14 changed files with 341 additions and 89 deletions

View File

@ -1,3 +1,17 @@
# Upgrade to 2.6
## Minor BC BREAK: removed `Doctrine\ORM\Query\Parser#isInternalFunction`
Method `Doctrine\ORM\Query\Parser#isInternalFunction` was removed because
the distinction between internal function and user defined DQL was removed.
[#6500](https://github.com/doctrine/doctrine2/pull/6500)
## Minor BC BREAK: removed `Doctrine\ORM\ORMException#overwriteInternalDQLFunctionNotAllowed`
Method `Doctrine\ORM\Query\Parser#overwriteInternalDQLFunctionNotAllowed` was
removed because of the choice to allow users to overwrite internal functions, ie
`AVG`, `SUM`, `COUNT`, `MIN` and `MAX`. [#6500](https://github.com/doctrine/doctrine2/pull/6500)
# Upgrade to 2.5
## Minor BC BREAK: removed `Doctrine\ORM\Query\SqlWalker#walkCaseExpression()`

View File

@ -420,15 +420,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string|callable $className Class name or a callable that returns the function.
*
* @return void
*
* @throws ORMException
*/
public function addCustomStringFunction($name, $className)
{
if (Query\Parser::isInternalFunction($name)) {
throw ORMException::overwriteInternalDQLFunctionNotAllowed($name);
}
$this->_attributes['customStringFunctions'][strtolower($name)] = $className;
}
@ -478,15 +472,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string|callable $className Class name or a callable that returns the function.
*
* @return void
*
* @throws ORMException
*/
public function addCustomNumericFunction($name, $className)
{
if (Query\Parser::isInternalFunction($name)) {
throw ORMException::overwriteInternalDQLFunctionNotAllowed($name);
}
$this->_attributes['customNumericFunctions'][strtolower($name)] = $className;
}
@ -536,15 +524,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string|callable $className Class name or a callable that returns the function.
*
* @return void
*
* @throws ORMException
*/
public function addCustomDatetimeFunction($name, $className)
{
if (Query\Parser::isInternalFunction($name)) {
throw ORMException::overwriteInternalDQLFunctionNotAllowed($name);
}
$this->_attributes['customDatetimeFunctions'][strtolower($name)] = $className;
}

View File

@ -323,16 +323,6 @@ class ORMException extends Exception
);
}
/**
* @param string $functionName
*
* @return ORMException
*/
public static function overwriteInternalDQLFunctionNotAllowed($functionName)
{
return new self("It is not allowed to overwrite internal function '$functionName' in the DQL parser through user-defined functions.");
}
/**
* @return ORMException
*/

View File

@ -0,0 +1,54 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST\Functions;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\AST\AggregateExpression;
/**
* "AVG" "(" ["DISTINCT"] StringPrimary ")"
*
* @since 2.6
* @author Mathew Davies <thepixeldeveloper@icloud.com>
*/
final class AvgFunction extends FunctionNode
{
/**
* @var AggregateExpression
*/
private $aggregateExpression;
/**
* @inheritDoc
*/
public function getSql(SqlWalker $sqlWalker): string
{
return $this->aggregateExpression->dispatch($sqlWalker);
}
/**
* @inheritDoc
*/
public function parse(Parser $parser): void
{
$this->aggregateExpression = $parser->AggregateExpression();
}
}

View File

@ -0,0 +1,54 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST\Functions;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\AST\AggregateExpression;
/**
* "COUNT" "(" ["DISTINCT"] StringPrimary ")"
*
* @since 2.6
* @author Mathew Davies <thepixeldeveloper@icloud.com>
*/
final class CountFunction extends FunctionNode
{
/**
* @var AggregateExpression
*/
private $aggregateExpression;
/**
* @inheritDoc
*/
public function getSql(SqlWalker $sqlWalker): string
{
return $this->aggregateExpression->dispatch($sqlWalker);
}
/**
* @inheritDoc
*/
public function parse(Parser $parser): void
{
$this->aggregateExpression = $parser->AggregateExpression();
}
}

View File

@ -0,0 +1,54 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST\Functions;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\AST\AggregateExpression;
/**
* "MAX" "(" ["DISTINCT"] StringPrimary ")"
*
* @since 2.6
* @author Mathew Davies <thepixeldeveloper@icloud.com>
*/
final class MaxFunction extends FunctionNode
{
/**
* @var AggregateExpression
*/
private $aggregateExpression;
/**
* @inheritDoc
*/
public function getSql(SqlWalker $sqlWalker): string
{
return $this->aggregateExpression->dispatch($sqlWalker);
}
/**
* @inheritDoc
*/
public function parse(Parser $parser): void
{
$this->aggregateExpression = $parser->AggregateExpression();
}
}

View File

@ -0,0 +1,54 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST\Functions;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\AST\AggregateExpression;
/**
* "MIN" "(" ["DISTINCT"] StringPrimary ")"
*
* @since 2.6
* @author Mathew Davies <thepixeldeveloper@icloud.com>
*/
final class MinFunction extends FunctionNode
{
/**
* @var AggregateExpression
*/
private $aggregateExpression;
/**
* @inheritDoc
*/
public function getSql(SqlWalker $sqlWalker): string
{
return $this->aggregateExpression->dispatch($sqlWalker);
}
/**
* @inheritDoc
*/
public function parse(Parser $parser): void
{
$this->aggregateExpression = $parser->AggregateExpression();
}
}

View File

@ -0,0 +1,54 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST\Functions;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\AST\AggregateExpression;
/**
* "SUM" "(" ["DISTINCT"] StringPrimary ")"
*
* @since 2.6
* @author Mathew Davies <thepixeldeveloper@icloud.com>
*/
final class SumFunction extends FunctionNode
{
/**
* @var AggregateExpression
*/
private $aggregateExpression;
/**
* @inheritDoc
*/
public function getSql(SqlWalker $sqlWalker): string
{
return $this->aggregateExpression->dispatch($sqlWalker);
}
/**
* @inheritDoc
*/
public function parse(Parser $parser): void
{
$this->aggregateExpression = $parser->AggregateExpression();
}
}

View File

@ -65,6 +65,13 @@ class Parser
'date_diff' => Functions\DateDiffFunction::class,
'bit_and' => Functions\BitAndFunction::class,
'bit_or' => Functions\BitOrFunction::class,
// Aggregate functions
'min' => Functions\MinFunction::class,
'max' => Functions\MaxFunction::class,
'avg' => Functions\AvgFunction::class,
'sum' => Functions\SumFunction::class,
'count' => Functions\CountFunction::class,
];
/**
@ -171,23 +178,6 @@ class Parser
*/
private $identVariableExpressions = [];
/**
* Checks if a function is internally defined. Used to prevent overwriting
* of built-in functions through user-defined functions.
*
* @param string $functionName
*
* @return bool
*/
static public function isInternalFunction($functionName)
{
$functionName = strtolower($functionName);
return isset(self::$_STRING_FUNCTIONS[$functionName])
|| isset(self::$_DATETIME_FUNCTIONS[$functionName])
|| isset(self::$_NUMERIC_FUNCTIONS[$functionName]);
}
/**
* Creates a new query parser object.
*
@ -1978,9 +1968,6 @@ class Parser
// SUM(u.id) + COUNT(u.id)
return $this->SimpleArithmeticExpression();
case ($this->isAggregateFunction($this->lexer->lookahead['type'])):
return $this->AggregateExpression();
default:
// IDENTITY(u)
return $this->FunctionDeclaration();
@ -2209,11 +2196,6 @@ class Parser
$expression = $this->ScalarExpression();
break;
case ($this->isAggregateFunction($lookaheadType)):
// COUNT(u.id)
$expression = $this->AggregateExpression();
break;
default:
// IDENTITY(u)
$expression = $this->FunctionDeclaration();
@ -2858,10 +2840,6 @@ class Parser
$peek = $this->lexer->glimpse();
if ($peek['value'] == '(') {
if ($this->isAggregateFunction($this->lexer->lookahead['type'])) {
return $this->AggregateExpression();
}
return $this->FunctionDeclaration();
}
@ -2932,11 +2910,6 @@ class Parser
case Lexer::T_COALESCE:
case Lexer::T_NULLIF:
return $this->CaseExpression();
default:
if ($this->isAggregateFunction($lookaheadType)) {
return $this->AggregateExpression();
}
}
$this->syntaxError(
@ -3236,10 +3209,6 @@ class Parser
$expr = $this->CoalesceExpression();
break;
case $this->isAggregateFunction($this->lexer->lookahead['type']):
$expr = $this->AggregateExpression();
break;
case $this->isFunction():
$expr = $this->FunctionDeclaration();
break;
@ -3376,8 +3345,13 @@ class Parser
$token = $this->lexer->lookahead;
$funcName = strtolower($token['value']);
// Check for built-in functions first!
$customFunctionDeclaration = $this->CustomFunctionDeclaration();
// Check for custom functions functions first!
switch (true) {
case $customFunctionDeclaration !== null:
return $customFunctionDeclaration;
case (isset(self::$_STRING_FUNCTIONS[$funcName])):
return $this->FunctionsReturningStrings();
@ -3388,7 +3362,7 @@ class Parser
return $this->FunctionsReturningDatetime();
default:
return $this->CustomFunctionDeclaration();
$this->syntaxError('known function', $token);
}
}
@ -3416,7 +3390,7 @@ class Parser
return $this->CustomFunctionsReturningDatetime();
default:
$this->syntaxError('known function', $token);
return null;
}
}

View File

@ -1579,12 +1579,6 @@ class SqlWalker implements TreeWalker
$sql .= $this->walkPathExpression($expr);
break;
case ($expr instanceof AST\AggregateExpression):
$alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++;
$sql .= $this->walkAggregateExpression($expr) . ' AS dctrn__' . $alias;
break;
case ($expr instanceof AST\Subselect):
$alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++;

View File

@ -265,8 +265,6 @@ class ConfigurationTest extends TestCase
$this->assertSame(null, $this->configuration->getCustomStringFunction('NonExistingFunction'));
$this->configuration->setCustomStringFunctions(['OtherFunctionName' => __CLASS__]);
$this->assertSame(__CLASS__, $this->configuration->getCustomStringFunction('OtherFunctionName'));
$this->expectException(ORMException::class);
$this->configuration->addCustomStringFunction('concat', __CLASS__);
}
public function testAddGetCustomNumericFunction()
@ -276,8 +274,6 @@ class ConfigurationTest extends TestCase
$this->assertSame(null, $this->configuration->getCustomNumericFunction('NonExistingFunction'));
$this->configuration->setCustomNumericFunctions(['OtherFunctionName' => __CLASS__]);
$this->assertSame(__CLASS__, $this->configuration->getCustomNumericFunction('OtherFunctionName'));
$this->expectException(ORMException::class);
$this->configuration->addCustomNumericFunction('abs', __CLASS__);
}
public function testAddGetCustomDatetimeFunction()
@ -287,8 +283,6 @@ class ConfigurationTest extends TestCase
$this->assertSame(null, $this->configuration->getCustomDatetimeFunction('NonExistingFunction'));
$this->configuration->setCustomDatetimeFunctions(['OtherFunctionName' => __CLASS__]);
$this->assertSame(__CLASS__, $this->configuration->getCustomDatetimeFunction('OtherFunctionName'));
$this->expectException(ORMException::class);
$this->configuration->addCustomDatetimeFunction('date_add', __CLASS__);
}
public function testAddGetCustomHydrationMode()

View File

@ -47,6 +47,23 @@ class CustomFunctionsTest extends OrmFunctionalTestCase
$this->assertEquals(1, count($users));
$this->assertSame($user, $users[0]);
}
public function testCustomFunctionOverride()
{
$user = new CmsUser();
$user->name = 'Bob';
$user->username = 'Dylan';
$this->_em->persist($user);
$this->_em->flush();
$this->_em->getConfiguration()->addCustomStringFunction('COUNT', 'Doctrine\Tests\ORM\Functional\CustomCount');
$query = $this->_em->createQuery('SELECT COUNT(DISTINCT u.id) FROM Doctrine\Tests\Models\CMS\CmsUser u');
$usersCount = $query->getSingleScalarResult();
$this->assertEquals(1, $usersCount);
}
}
class NoOp extends FunctionNode
@ -70,3 +87,20 @@ class NoOp extends FunctionNode
}
}
class CustomCount extends FunctionNode
{
/**
* @var Query\AST\AggregateExpression
*/
private $aggregateExpression;
public function parse(Parser $parser): void
{
$this->aggregateExpression = $parser->AggregateExpression();
}
public function getSql(SqlWalker $sqlWalker): string
{
return $this->aggregateExpression->dispatch($sqlWalker);
}
}

View File

@ -1031,7 +1031,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
"SELECT u.name, (SELECT COUNT(p.phonenumber) FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234) pcount FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'",
"SELECT c0_.name AS name_0, (SELECT COUNT(c1_.phonenumber) AS dctrn__1 FROM cms_phonenumbers c1_ WHERE c1_.phonenumber = 1234) AS sclr_1 FROM cms_users c0_ WHERE c0_.name = 'jon'"
"SELECT c0_.name AS name_0, (SELECT COUNT(c1_.phonenumber) AS sclr_2 FROM cms_phonenumbers c1_ WHERE c1_.phonenumber = 1234) AS sclr_1 FROM cms_users c0_ WHERE c0_.name = 'jon'"
);
}
@ -1198,7 +1198,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
"SELECT u.name, (SELECT COUNT(cfc.id) total FROM Doctrine\Tests\Models\Company\CompanyFixContract cfc) as cfc_count FROM Doctrine\Tests\Models\CMS\CmsUser u",
"SELECT c0_.name AS name_0, (SELECT COUNT(c1_.id) AS dctrn__total FROM company_contracts c1_ WHERE c1_.discr IN ('fix')) AS sclr_1 FROM cms_users c0_"
"SELECT c0_.name AS name_0, (SELECT COUNT(c1_.id) AS sclr_2 FROM company_contracts c1_ WHERE c1_.discr IN ('fix')) AS sclr_1 FROM cms_users c0_"
);
}
@ -1750,7 +1750,7 @@ class SelectSqlGenerationTest extends OrmTestCase
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE COUNT(u1.id) = ( SELECT SUM(u2.id) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE COUNT(c0_.id) = (SELECT SUM(c1_.id) AS dctrn__1 FROM cms_users c1_)'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE COUNT(c0_.id) = (SELECT SUM(c1_.id) AS sclr_4 FROM cms_users c1_)'
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE COUNT(u1.id) <= ( SELECT SUM(u2.id) + COUNT(u2.email) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',

View File

@ -330,7 +330,7 @@ ORDER BY b.id DESC'
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
$this->assertEquals(
'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 dctrn__1 FROM BlogPost b1_) = 1)) dctrn_result ORDER BY id_0 DESC',
'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 ORDER BY id_0 DESC',
$query->getSQL()
);
}
@ -346,7 +346,7 @@ ORDER BY b.id DESC'
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
$this->assertEquals(
'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 dctrn__1 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',
$query->getSQL()
);
}
@ -390,7 +390,7 @@ ORDER BY b.id DESC'
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
$this->assertEquals(
'SELECT DISTINCT id_0 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS dctrn__1 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2 FROM Author a0_) dctrn_result ORDER BY sclr_2 DESC',
'SELECT DISTINCT id_0 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 ORDER BY sclr_2 DESC',
$query->getSQL()
);
}
@ -415,7 +415,7 @@ ORDER BY b.id DESC'
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
$this->assertEquals(
'SELECT DISTINCT id_0, MIN(sclr_3) AS dctrn_minrownum FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS dctrn__1 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2, ROW_NUMBER() OVER(ORDER BY (SELECT MIN(m1_.title) AS dctrn__2 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) DESC) AS sclr_3 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',
$query->getSQL()
);
}
@ -440,7 +440,7 @@ ORDER BY b.id DESC'
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class);
$this->assertEquals(
'SELECT DISTINCT ID_0, MIN(SCLR_3) AS dctrn_minrownum FROM (SELECT a0_.id AS ID_0, a0_.name AS NAME_1, (SELECT MIN(m1_.title) AS dctrn__1 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS SCLR_2, ROW_NUMBER() OVER(ORDER BY (SELECT MIN(m1_.title) AS dctrn__2 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) DESC) AS SCLR_3 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',
$query->getSQL()
);
}